如何在NestJS中让Sequelize指定第二个数据库创建事务
解决NestJS + Sequelize多数据库下事务绑定指定连接的问题
我之前在NestJS结合Sequelize做多数据库开发时,也踩过一模一样的坑——明明指定了第二个数据库连接,但事务总是跑到第一个库上,甚至还会提前提交。咱们来一步步解决这个问题:
问题场景回顾
你在app.module.ts里配置了两个PostgreSQL连接,第二个连接指定了name: connection_2_NAME,但在ExportService里创建事务时,始终默认用第一个连接,而且事务会在第一个查询成功后就提交。
原配置与代码
app.module.ts(你的原配置):
@Module({ imports: [ SequelizeModule.forRoot({ dialect: 'postgres', host: connection_1_dbserver, port: connection_1_port, username: connection_1_username, password: connection_1_pass, database: connection_1_dbname, models: [...], synchronize: false, }), SequelizeModule.forRoot({ dialect: 'postgres', name: connection_2_NAME, host: connection_2_dbserver, port: connection_2_port, username: connection_2_username, password: connection_2_pass, database: connection_2_dbname, models: [...], synchronize: false, }) ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
原ExportService代码:
@Injectable() export class ExportService { constructor( @InjectConnection(connection_2_NAME) private readonly connection_2_name_ref, private sequelize: Sequelize, ) {} public async export(id: number): Promise<{ code: number }> { let result = { code: 1 }; // ...其他逻辑 try { return this.connection_2_NAME.transaction(transaction => { // First query return this.removeCurrData( id, transaction, ) .then(() => { // Second query return this.insertNewData(newData, id, transaction); }) .then(exportResult => { if (exportResult) { result.code = 3; } else result.code = 2; return result; }); }); } catch (error) { result.code = 2; return result; } // ...其他逻辑 } }
问题根源
你这里有两个关键问题:
- 注入时同时保留了默认的
Sequelize实例(对应第一个数据库连接)和指定连接的引用,容易混淆; - 调用事务时用了
this.connection_2_NAME.transaction()——这里不仅是变量名写错了(你注入的是connection_2_name_ref),更重要的是,你需要直接把指定连接注入为Sequelize实例,才能确保事务绑定到这个连接上。
正确解决方案
第一步:修正依赖注入
只注入你需要的第二个数据库连接对应的Sequelize实例,去掉多余的默认实例:
@Injectable() export class ExportService { // 直接将指定连接注入为Sequelize实例 constructor( @InjectConnection(connection_2_NAME) private readonly sequelize: Sequelize, ) {} // ...其他代码 }
第二步:正确创建并使用事务
用这个注入的sequelize实例创建事务,推荐使用async/await语法让代码更清晰(也可以继续用Promise链式调用,但async/await可读性更高):
public async export(id: number): Promise<{ code: number }> { let result = { code: 1 }; // ...其他前置逻辑 try { // 用指定连接的Sequelize实例创建事务 return this.sequelize.transaction(async (t) => { // 第一个查询:传入事务对象t await this.removeCurrData(id, t); // 第二个查询:同样传入事务对象t const exportResult = await this.insertNewData(newData, id, t); result.code = exportResult ? 3 : 2; return result; }); } catch (error) { result.code = 2; return result; } }
这样创建的事务就会完全绑定到你配置的第二个数据库连接上,不会再跑到第一个库,也不会提前提交了——事务会在所有查询执行完成后才统一提交,一旦中间有任何错误就会回滚。
我也是在学习过程中踩过这个坑,希望这个解决方案能帮到你!编码愉快 ;)
内容的提问来源于stack exchange,提问作者Janixa
相关产品推荐
相关产品推荐

