为何TypeORM事务仅处理前10条数据?NestJS服务崩溃排查
问题原因分析与解决方案
核心原因:数据库连接池耗尽
TypeORM 默认的数据库连接池大小是 10,意味着同一时间最多只能有10个活跃的数据库连接/事务。
- 把打印逻辑放到事务内部时,每个异步任务必须先成功获取数据库连接、开启事务,才能执行
console.log。前10个任务顺利拿到连接并打印,剩下的5个任务会进入等待队列,长时间等待连接会触发超时或未捕获的Promise异常,最终导致服务崩溃。 - 事务外部打印的场景下,
console.log在请求数据库连接前就执行了,所以15条索引会被快速全部打印,之后才逐个发起事务请求——连接池会排队处理,但打印动作已经完成,不会出现“只打印前10条”的现象。
代码中的潜在问题
- 并发事务数超过连接池上限:直接用
map发起15个并发事务,超过默认连接池容量,引发资源竞争。 - 未处理异步任务的完成状态:生成的
promises数组没有用Promise.all包裹,NestJS无法感知这些异步任务的执行状态,请求结束时可能强制终止未完成任务,导致崩溃。 - 事务内误用全局EntityManager:你在事务内部调用的
super.findOne和userService.findOne,默认使用全局的EntityManager而非事务专属的transactionalEntityManager——这会让查询脱离事务上下文,同时进一步消耗连接池资源。
修复方案
1. 限制并发事务数量
用p-limit这类工具控制并发数(匹配连接池大小),同时用Promise.all等待所有任务完成:
import pLimit from 'p-limit'; const limit = pLimit(10); // 与连接池大小保持一致 const promises = body.body.map((bodyConfirm, id) => limit(async () => { await this.entityManager.transaction(async transactionalEntityManager => { console.log('id -> ', id); // 使用事务内的EntityManager执行查询 const incidentCurrent = await transactionalEntityManager.findOne(IncidentEntity, { where: { id: bodyConfirm.id }, relations: ['incident_management_users'] }); const proContactUser = await transactionalEntityManager.findOne(UserEntity, { where: { user_name: incidentCurrent.incident_management_users.user_name, telegram: Not(IsNull()) } }); }); })); await Promise.all(promises); // 等待所有异步任务执行完毕
2. 调整数据库连接池大小(可选)
如果业务确实需要更高并发,可以在TypeORM配置中增大connectionLimit,但要注意数据库服务器的承载能力:
// TypeORM配置文件或NestJS的TypeORM模块配置 { type: 'mysql', // 替换为你的数据库类型 host: 'localhost', port: 3306, username: 'your_username', password: 'your_password', database: 'your_db', entities: [__dirname + '/**/*.entity{.ts,.js}'], synchronize: false, extra: { connectionLimit: 20 // 增大连接池上限 } }
3. 确保事务内使用专属EntityManager
事务中所有数据库操作必须使用回调提供的transactionalEntityManager,避免使用全局实例或Service中的默认EntityManager,确保操作处于事务上下文内。
内容的提问来源于stack exchange,提问作者Hoang Son
相关产品推荐
相关产品推荐

