Node.js实现MS SQL多存储过程事务遇回滚报错求助
问题原因及修复方案
核心错误原因
- 语法错误:
new sql.ConnectionPool(config))多了一个多余的右括号 - 时序逻辑错误:混用
await和.then导致异常触发时,仍有在途的数据库请求未完成,此时调用rollback就会触发Can't rollback transaction. There is a request in progress报错 - 并行执行逻辑错误:mssql库的单个事务绑定在单条连接上,同一时间仅支持执行一个请求,不支持并行跑多个存储过程,你代码中先串行
await了两个操作再用Promise.all属于无效写法,也可能引发请求冲突 - 冗余包装:
insertOperation和updateOperation方法中不需要手动封装Promise,request.execute本身就返回Promise,多余的封装反而可能引发逻辑异常
修复后代码
主执行方法
const executeProcedure = async (data1, data2) => { let dbConn = null; let transaction = null; try { // 初始化连接 dbConn = new sql.ConnectionPool(config); await dbConn.connect(); transaction = new sql.Transaction(dbConn); // 开启事务 await transaction.begin(); // 串行执行两个存储过程,单事务下不支持并行 await insertOperation(transaction, data1); await updateOperation(transaction, data2); // 全部执行成功提交事务 await transaction.commit(); return {}; } catch (error) { // 异常时回滚事务,此时所有请求已经执行完成,不会有在途请求 if (transaction) await transaction.rollback(); throw error; } finally { // 统一在finally中关闭连接,避免异常时连接泄漏 if (dbConn) await dbConn.close(); } }
简化后的存储过程调用方法
const insertOperation = async (transaction, data1) => { const request = new sql.Request(transaction); request.input('data1', sql.NVarChar(40), data1); const recordSet = await request.execute('dbo.insertOperation'); return recordSet.recordsets; } const updateOperation = async (transaction, data2) => { const request = new sql.Request(transaction); request.input('data2', sql.NVarChar(40), data2); const recordSet = await request.execute('dbo.updateOperation'); return recordSet.recordsets; }
额外优化点
- 用
try/finally统一处理连接关闭,避免异常场景下连接泄漏 - 移除了冗余的Promise封装和混用的
.then逻辑,全用await保证时序清晰 - 回滚前确认事务实例存在,避免空引用报错
内容的提问来源于stack exchange,提问作者Kmss
相关产品推荐
相关产品推荐

