abortTransaction()静默执行,不抛错;错误码仅能在CRUD操作或commitTransaction调用处捕获,事务自动中断时不会报告“回滚失败”。

事务回滚失败时为什么看不到错误?
因为 abortTransaction() 本身不抛错——它静默执行。你根本捕不到“回滚失败”这个动作的错误,除非它发生在显式调用 abortTransaction() 的那一刻(极少见),或者更常见的是:事务早已因某次操作失败而被自动中止,但你没在 insertOne、updateOne 等操作环节捕获错误码,误以为“没报错=成功”。
- 真正能拿到错误码的地方只有两个:
collection.insertOne()这类 CRUD 操作本身,或显式调用commitTransaction()的位置 -
withTransaction()内部抛出的错误,来自回调函数里任意一步(包括throw new Error()、未 catch 的 rejected promise),都会触发 abort,但错误源头仍在那一步,不是 abort 阶段 - 如果事务因网络断开、会话过期被静默中断,驱动不会告诉你“回滚失败”,只会让后续操作报
Transaction is not in progress
为什么 commitTransaction 报错 code: 112 却不是写冲突?
code: 112 名义叫 NoSuchTransaction,但实际表示事务上下文已丢失——可能是心跳超时导致节点被标记为不可用、serverSelectionTimeoutMS 先于事务完成就触发、或连接被中间件(如 SLB)主动切断。它和 code: 133(WriteConflict)是两回事。
- 检查
heartbeatFrequencyMS是否匹配真实网络延迟:跨 AZ 场景 RTT ≈ 80ms 时,设为2000,而非默认10000 - 确认
transactionLifetimeLimitSeconds(服务端参数)是否 ≥ 你事务最长可能耗时;本地开发建议设为180 - 避免在事务回调里做耗时同步操作(如 fs.readFileSync),它会阻塞事件循环,间接拉长事务时间
如何确保事务内每步失败都能定位到具体原因?
别依赖 error.name 做判断,MongoDB 驱动对不同失败场景返回不同构造的错误对象,唯一稳定字段是 error.code 和(对批量操作)error.writeErrors。
-
code: 11000→ 唯一键冲突,需检查数据去重逻辑或改用updateOne({ upsert: true }) -
code: 133→ 写冲突,若启用retryWrites: true,驱动会自动重试该操作(非整个事务) -
code: 121→ Schema 验证失败,检查required或自定义validate规则 -
error.errorLabels?.includes('TransientTransactionError')比error.name === 'MongoTransientTransactionError'更可靠,用于决定是否重试整个事务
withTransaction() 里忘记传 session 选项会怎样?
所有 CRUD 操作(insertOne、updateMany 等)都必须显式带上 { session },漏一个就脱离事务上下文——它不会报错,但那条操作会立即提交,其余操作还在事务里,最终造成数据不一致。
-
client.startSession()必须在client.connect()之后调用,否则session对象为空 - 事务结束后不能复用同一
session对象,要重用就得先session.endSession(),再client.startSession() - 回调函数必须返回 Promise,否则
withTransaction()会直接 resolve 并 commit,哪怕里面还有异步操作没跑完


















