MongoDB事务不会自动回滚,必须显式调用session.abortTransaction()或依赖会话超时(不推荐);其原子性依赖WiredTiger MVCC与复制协议协同,仅在commitTransaction获w:"majority"确认后才持久化。

网络分区发生时,MongoDB 事务不会“自动回滚”,而是被阻塞或失败——关键在于它根本无法提交,而不是事后撤回已写内容。
为什么 w: "majority" 写入会在分区时卡住或报 NotMaster
当副本集因网络隔离分裂成两个子集(比如 3 节点变 2+1),少数派节点虽显示 "stateStr" : "PRIMARY",但其 isMaster 响应中 ismaster 为 true、hosts 列表却只剩自己。此时所有带 w: "majority" 的写操作:
- 在多数派 PRIMARY 上能正常进入写入流程,等待多数节点 journal 持久化确认
- 在少数派 “假主” 上直接拒绝,返回
WriteResult({ "ok" : 0, "errmsg" : "not master" })或InterruptedDueToReplStateChange - 若客户端未设超时,
w: "majority"请求会挂起约 30 秒(默认writeConcernTimeoutMS)后失败
事务提交前必须满足 majority 确认,否则不落盘
MongoDB 事务的原子性依赖于 WiredTiger 的 MVCC + 复制协议协同。事务内所有操作先写入会话级暂存区,只有在 commitTransaction 阶段成功获得 w: "majority" 确认后,才触发 CheckPoint 和 Journal 刷盘。这意味着:
- 分区期间发起的事务,只要没收到 majority 确认,就永远停留在内存暂存区,不会写入磁盘
- 一旦客户端断开或超时,驱动自动丢弃该会话,暂存数据被清除——看起来像“回滚”,实则是从未真正提交
- 若某节点未启用
journal: true(即storage.journal.enabled: false),即使它参与了 majority 投票,崩溃后仍可能丢失已确认的写入,导致事务最终回滚
如何让应用在分区时快速感知并降级处理
不能靠事后查日志,得在写之前做轻量探测。推荐在事务启动前加一次 isMaster 校验:
db.runCommand({ isMaster: 1 })
检查返回值是否同时满足:
ismaster === true-
hosts.length === 3(假设是 3 节点副本集) -
passive === false且hidden === false
任一条件不满足,立即放弃事务,走本地缓存或异步补偿逻辑。注意:不要用 rs.status() 替代,它本身可能因网络问题超时或返回陈旧视图。
分片集群下事务的额外限制与风险
跨分片事务(即涉及多个 shard 的事务)在分区时更脆弱:
- mongos 必须与 config server + 所有目标 shard 保持通信,任一链路中断即失败
- 事务协调器(coordinator)所在 shard 若被隔离,整个事务无法推进
- 4.4+ 支持的 hedged reads 对事务无帮助——事务读必须走快照一致性路径,不支持对冲
- 生产环境应避免跨分片事务;如必须使用,确保每个 shard 自身是 3 节点副本集,并全局启用
journal
真正难处理的不是“怎么回滚”,而是“怎么不让事务走到需要回滚那一步”——校验、超时、降级、配置加固,每一步漏掉都可能让服务在分区中静默失联数分钟。











