You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Knex操作MSSQL事务报非LoggedIn状态错误、连接重置问题

问题环境
  • 运行时:Node 10.21.0
  • 依赖版本:knex@^0.16.3、mssql@^4.1.0
问题复现代码

事务调用逻辑:

await this.repository.transaction(async (transaction) => {
  try {
    await this.repository.deleteData(transaction);
    result = await this.repository.postData(data, transaction);
    await transaction.commit();          
  } catch (e) {
    await transaction.rollback();
    throw (e);
  }
});

Repository层对应方法:

async deleteData(transaction) {
  const result = await this.knex.raw(`
    DELETE Table1
  `)
    .transacting(transaction);

  return result;
}

async postData(data, transaction) {
  const query = this.knex.batchInsert('Table1', data, 10)
    .returning('id')
    .transacting(transaction);

  const result = await query;

  return result;
}

运行抛出错误:

TransactionError: Requests can only be made in the LoggedIn state, not the Final state
ConnectionError: Connection lost - write ECONNRESET, "Connection Closed before request completed"

问题诱因

核心原因是Knex事务生命周期管理逻辑冲突:

  • 当向knex.transaction()传入异步回调函数时,Knex默认开启自动事务管理:回调内所有异步操作正常resolve则自动提交事务,回调抛出异常则自动回滚事务,不需要手动调用commit()/rollback()。
  • 代码中在回调内手动执行commit()后,事务绑定的数据库连接已经进入Final结束状态、被归还到连接池。此时Knex在回调执行完成后,还会尝试执行自动收尾的事务状态操作,向已经关闭的连接发送请求,就会触发状态不合法的报错,后续连接被强制重置就会抛出ECONNRESET、请求完成前连接关闭的异常。
  • 当前使用的mssql@4.1.0驱动对连接状态校验严格,重复提交/回滚事务的操作不会被静默忽略,会直接抛出异常打断执行。
修复方案

优先使用Knex自带的自动事务管理,删除回调内手动的commit、rollback和冗余try/catch逻辑,修改后的事务代码如下:

result = await this.repository.transaction(async (transaction) => {
  await this.repository.deleteData(transaction);
  return this.repository.postData(data, transaction);
});

逻辑说明:

  • 只要deleteData或postData任意一步抛出错误,Knex会自动执行回滚,异常会正常向外抛出,不需要手动处理。
  • 所有操作执行成功后Knex会自动提交事务,回调的返回值会作为transaction()方法的执行结果赋值给result。

如果确实需要手动控制事务提交/回滚节点,就不要给transaction()传入回调,手动获取事务对象处理,写法如下:

const transaction = await this.repository.transaction();
try {
  await this.repository.deleteData(transaction);
  result = await this.repository.postData(data, transaction);
  await transaction.commit();
} catch (e) {
  await transaction.rollback();
  throw e;
}

额外注意:当前deleteData方法内的DELETE Table1语句没有WHERE条件,会清空整张表的数据,如果不是业务预期的全表删除操作,请补充对应过滤条件,避免数据误删。

内容的提问来源于stack exchange,提问作者Developer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 17:18:06