6.0 KiB
6.0 KiB
数据库连接模块使用指南
目录
简介
数据库连接模块提供了一套高效的数据库连接管理系统,基于连接池实现,用于管理系统级数据库和团队级数据库的连接。主要特点:
- 使用高阶函数中间件模式,易于集成到API路由
- 基于
mysql2/promise
的连接池,提供高性能的连接复用 - 自动管理连接的获取和释放,防止连接泄漏
- 分离的系统和团队数据库连接逻辑,支持多租户架构
- 完善的日志系统,方便调试和监控
文件结构
src/lib/db/
├── config.ts # 数据库配置
├── connect-system.ts # 系统数据库连接
├── connect-team.ts # 团队数据库连接
└── index.ts # 统一导出入口
基本用法
系统数据库连接
系统数据库用于存储全局数据,如用户账户、工作空间和团队信息。
// 导入系统数据库连接
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);
团队数据库连接
团队数据库用于存储特定团队的数据,每个团队可以使用独立的数据库。
// 导入团队数据库连接
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);
数据库查询最佳实践
- 使用参数化查询
参数化查询是防止SQL注入的最佳方式:
// 良好实践 - 使用参数化查询
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}`
);
- 只查询需要的列
为提高性能,只查询实际需要的列:
// 良好实践 - 只查询需要的列
const [rows] = await req.db.query(
'SELECT id, name, email FROM users'
);
// 不良实践 - 查询所有列
const [rows] = await req.db.query(
'SELECT * FROM users'
);
- 使用事务保证数据一致性
当需要进行多个相关操作时,使用事务确保数据一致性:
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()
:
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;
}
问:如何处理大量并发请求?
答:当前连接池配置应该足以处理中等负载。如果需要处理高并发,考虑:
- 增加连接池大小(修改
connectionLimit
) - 添加缓存层减少数据库查询
- 实现请求节流或批处理
问:连接池中的连接是如何管理的?
答:连接池自动管理连接的创建、分配和回收:
- 首次请求时,创建连接并添加到池中
- 处理完请求后,连接被释放回池中(而不是关闭)
- 连接有最大空闲时间,超时会被关闭
- 连接池有最大连接数限制,超过限制的请求会等待
// 不需要手动关闭连接
// 中间件会自动处理释放连接
const connection = await systemPool.getConnection();
try {
// 使用连接...
const [rows] = await connection.query('SELECT ...');
return rows;
} finally {
// 中间件会自动调用这一行
connection.release();
}
文档由阿瑞创建和维护。如有问题,请联系系统管理员。