# 数据库连接模块使用指南 ## 目录 - [简介](#简介) - [文件结构](#文件结构) - [基本用法](#基本用法) - [系统数据库连接](#系统数据库连接) - [团队数据库连接](#团队数据库连接) - [数据库查询最佳实践](#数据库查询最佳实践) - [性能考虑](#性能考虑) - [常见问题](#常见问题) ## 简介 数据库连接模块提供了一套高效的数据库连接管理系统,基于连接池实现,用于管理系统级数据库和团队级数据库的连接。主要特点: - 使用高阶函数中间件模式,易于集成到API路由 - 基于`mysql2/promise`的连接池,提供高性能的连接复用 - 自动管理连接的获取和释放,防止连接泄漏 - 分离的系统和团队数据库连接逻辑,支持多租户架构 - 完善的日志系统,方便调试和监控 ## 文件结构 ``` src/lib/db/ ├── config.ts # 数据库配置 ├── connect-system.ts # 系统数据库连接 ├── connect-team.ts # 团队数据库连接 └── index.ts # 统一导出入口 ``` ## 基本用法 ### 系统数据库连接 系统数据库用于存储全局数据,如用户账户、工作空间和团队信息。 ```typescript // 导入系统数据库连接 import { connectSystemDB, RequestWithDB } from '@/lib/db'; // 定义处理器函数 async function handler(req: RequestWithDB) { try { // 使用req.db访问数据库连接 const [rows] = await req.db.query('SELECT * FROM your_table'); // 处理结果 return rows; } catch (error) { console.error('数据库操作失败:', error); throw error; } } // 使用中间件包装处理函数 export const processData = connectSystemDB(handler); ``` ### 团队数据库连接 团队数据库用于存储特定团队的数据,每个团队可以使用独立的数据库。 ```typescript // 导入团队数据库连接 import { connectTeamDB, RequestWithDB } from '@/lib/db'; // 假设已获取团队数据库配置 const teamDbConfig = { host: 'localhost', name: 'team_db', user: 'team_user', password: 'team_password' }; // 定义处理器函数 async function handler(req: RequestWithDB) { try { // 使用req.db访问数据库连接 const [rows] = await req.db.query('SELECT * FROM team_data'); // 处理结果 return rows; } catch (error) { console.error('数据库操作失败:', error); throw error; } } // 使用中间件包装处理函数并创建处理函数 export const processTeamData = connectTeamDB( teamDbConfig.host, teamDbConfig.name, teamDbConfig.user, teamDbConfig.password )(handler); ``` ## 数据库查询最佳实践 1. **使用参数化查询** 参数化查询是防止SQL注入的最佳方式: ```typescript // 良好实践 - 使用参数化查询 const [user] = await req.db.query( 'SELECT id, username FROM users WHERE id = ?', [userId] ); // 不良实践 - 容易遭受SQL注入 const [user] = await req.db.query( `SELECT * FROM users WHERE id = ${userId}` ); ``` 2. **只查询需要的列** 为提高性能,只查询实际需要的列: ```typescript // 良好实践 - 只查询需要的列 const [rows] = await req.db.query( 'SELECT id, name, email FROM users' ); // 不良实践 - 查询所有列 const [rows] = await req.db.query( 'SELECT * FROM users' ); ``` 3. **使用事务保证数据一致性** 当需要进行多个相关操作时,使用事务确保数据一致性: ```typescript try { await req.db.beginTransaction(); // 执行多个查询 await req.db.query('INSERT INTO orders (user_id, total) VALUES (?, ?)', [userId, total]); const [result] = await req.db.query('SELECT LAST_INSERT_ID() as id'); const orderId = result[0].id; for (const item of items) { await req.db.query( 'INSERT INTO order_items (order_id, product_id, quantity) VALUES (?, ?, ?)', [orderId, item.productId, item.quantity] ); } await req.db.commit(); return orderId; } catch (error) { await req.db.rollback(); throw error; } ``` ## 性能考虑 连接池已经配置为最佳性能,但仍需注意: - 系统数据库连接池:最大10个连接 - 团队数据库连接池:每个团队最大5个连接 - 长时间运行的查询可能会耗尽连接池 - 确保查询有合适的索引 - 对大型结果集使用分页 ### 连接池监控 连接池状态可以在日志中查看。成功的连接操作会显示为绿色圆点(🟢),失败的操作会显示为红色圆点(🔴)。 ``` 🟢 MySQL 已连接: localhost:3306/saas_master 🟢 MySQL 系统数据库连接已获取 🟢 MySQL 系统数据库连接已释放 ``` ## 常见问题 ### 问:如何执行事务? **答**:使用`req.db.beginTransaction()`、`req.db.commit()`和`req.db.rollback()`: ```typescript try { await req.db.beginTransaction(); // 执行多个查询 await req.db.query('INSERT INTO ...'); await req.db.query('UPDATE ...'); await req.db.commit(); } catch (error) { await req.db.rollback(); throw error; } ``` ### 问:如何处理大量并发请求? **答**:当前连接池配置应该足以处理中等负载。如果需要处理高并发,考虑: 1. 增加连接池大小(修改`connectionLimit`) 2. 添加缓存层减少数据库查询 3. 实现请求节流或批处理 ### 问:连接池中的连接是如何管理的? **答**:连接池自动管理连接的创建、分配和回收: - 首次请求时,创建连接并添加到池中 - 处理完请求后,连接被释放回池中(而不是关闭) - 连接有最大空闲时间,超时会被关闭 - 连接池有最大连接数限制,超过限制的请求会等待 ```typescript // 不需要手动关闭连接 // 中间件会自动处理释放连接 const connection = await systemPool.getConnection(); try { // 使用连接... const [rows] = await connection.query('SELECT ...'); return rows; } finally { // 中间件会自动调用这一行 connection.release(); } ``` --- 文档由阿瑞创建和维护。如有问题,请联系系统管理员。