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

Mongoose使用withTransaction出现无限重试及事务不匹配报错问题

Mongoose withTransaction事务报错及无限重试问题排查

问题现象

使用Mongoose的withTransaction处理事务时出现两类报错,且触发无限重试(错误日志显示已重试1998次仍未停止),核心报错信息如下:

Mongodb Error withTransaction: Given transaction number 1 does not match any in-progress transactions. The active transaction number is -1

运行环境

  • MongoDB Server 4.4.x
  • mongoose ^5.10.0

withTransaction官方设计逻辑

Mongoose官方将withTransaction标注为事务最佳实践,该方法会自动处理以下逻辑:

  • 创建事务
  • 操作执行成功时提交事务
  • 操作抛出异常时中止事务
  • 出现临时事务错误时自动重试

问题代码

try {
  const session = await db.startSession();
  await session.withTransaction(() => {
    console.log('transaction in progress')
    return new Promise((resolve, reject) => {
      Promise.all([
        Model1().bulkWrite([...], { session }),
        Model2().bulkWrite([...], { session })
      ])
        .then(resp => {
          console.log('bulk write resolved successfully')
          resolve(resp)
        })
        .catch(error => {
          console.log('transaction error', error)
          reject(error)
        })
    })
  })
} catch (error) {
  console.error('withTransaction: ', error)
  throw error
} finally {
  session.endSession()
}

报错详情

错误1:NoSuchTransaction

transaction in progress
transaction error MongoError: Given transaction number 1998 does not match any in-progress transactions. The active transaction number is 1997
    at MessageStream.messageHandler (/var/task/node_modules/mongodb/lib/cmap/connection.js:299:20)
    at MessageStream.emit (events.js:400:28)
    at processIncomingData (/var/task/node_modules/mongodb/lib/cmap/message_stream.js:144:12)
    at MessageStream._write (/var/task/node_modules/mongodb/lib/cmap/message_stream.js:42:5)
    at writeOrBuffer (internal/streams/writable.js:358:12)
    at MessageStream.Writable.write (internal/streams/writable.js:303:10)
    at TLSSocket.ondata (internal/streams/readable.js:726:22)
    at TLSSocket.emit (events.js:400:28)
    at addChunk (internal/streams/readable.js:290:12)
    at readableAddChunk (internal/streams/readable.js:265:9)
    at TLSSocket.Readable.push (internal/streams/readable.js:204:10)
    at TLSWrap.onStreamRead (internal/stream_base_commons.js:188:23) {
  operationTime: Timestamp { _bsontype: 'Timestamp', low_: 1, high_: 1634234124 },
  ok: 0,
  code: 251,
  codeName: 'NoSuchTransaction',
  '$clusterTime': {
    clusterTime: Timestamp { _bsontype: 'Timestamp', low_: 1, high_: 1634234124 },
    signature: { hash: [Binary], keyId: [Long] }
  },
  [Symbol(errorLabels)]: Set(1) { 'TransientTransactionError' }
}

错误2:WriteConflict

transaction in progress
transaction error MongoError: WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.
    at MessageStream.messageHandler (/var/task/node_modules/mongodb/lib/cmap/connection.js:299:20)
    at MessageStream.emit (events.js:400:28)
    at processIncomingData (/var/task/node_modules/mongodb/lib/cmap/message_stream.js:144:12)
    at MessageStream._write (/var/task/node_modules/mongodb/lib/cmap/message_stream.js:42:5)
    at writeOrBuffer (internal/streams/writable.js:358:12)
    at MessageStream.Writable.write (internal/streams/writable.js:303:10)
    at TLSSocket.ondata (internal/streams/readable.js:726:22)
    at TLSSocket.emit (events.js:400:28)
    at addChunk (internal/streams/readable.js:290:12)
    at readableAddChunk (internal/streams/readable.js:265:9)
    at TLSSocket.Readable.push (internal/streams/readable.js:204:10)
    at TLSWrap.onStreamRead (internal/stream_base_commons.js:188:23) {
  operationTime: Timestamp { _bsontype: 'Timestamp', low_: 1, high_: 1634234124 },
  ok: 0,
  code: 112,
  codeName: 'WriteConflict',
  '$clusterTime': {
    clusterTime: Timestamp { _bsontype: 'Timestamp', low_: 1, high_: 1634234124 },
    signature: { hash: [Binary], keyId: [Long] }
  },
  [Symbol(errorLabels)]: Set(1) { 'TransientTransactionError' }
}

根因分析与解决方案

核心错误点

bulkWrite是Mongoose Model的静态方法,不能在Model实例上调用。问题代码中Model1().bulkWrite()的写法是先创建了Model1的实例,再调用实例上不存在的bulkWrite方法,导致session没有正确绑定到操作上,操作未加入当前事务,触发事务编号不匹配的错误。

解决方案

  1. 修正bulkWrite调用方式,直接调用Model的静态方法,确保session正确传递:
// 修正前(错误):Model1()返回实例,无静态bulkWrite方法
// Model1().bulkWrite([...], { session })
// 修正后(正确):直接调用Model的静态bulkWrite
Model1.bulkWrite([...], { session })
  1. 限制事务重试次数,避免无限重试。withTransaction默认对标记为TransientTransactionError的错误无重试上限,可通过配置maxRetryTimeMS参数限制最大重试时间:
await session.withTransaction(async () => {
  // 事务执行逻辑
}, {
  maxRetryTimeMS: 5000 // 最多重试5秒,可根据业务调整
})
  1. 排查并发操作冲突。WriteConflict报错说明有其他并发事务同时修改同一批数据,可通过调整业务逻辑避免同时操作相同资源,或增加分布式锁控制操作时序减少冲突概率。
  2. 若业务需要在事务内创建并保存单条文档,使用实例的save方法并传递session即可:
const newDoc = new Model1({ /* 文档字段 */ });
await newDoc.save({ session });

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 12:24:03