MongoDB分布式事务依赖Session上下文、日志复制和分片场景下的变体两阶段提交;需确保集群拓扑、存储引擎(WiredTiger)、副本集模式及writeConcern={"majority"}等配置匹配,否则事务失败或不持久。

MongoDB 的分布式事务不是靠中心协调器驱动的,而是依赖 Session 上下文 + 日志复制 + 变体两阶段提交(分片场景)协同完成。直接用 startTransaction() 并不能跨分片生效——必须确认集群拓扑、存储引擎和读写关注配置是否匹配。
Session 是事务的上下文载体,不是“开启事务”就完事了
Session 在 MongoDB 3.6 就已引入,4.0 才赋予其事务能力。它本质是服务端维护的一组关联元数据(lsid、txnNumber、stmtIds),用于把多个操作绑定到同一个逻辑单元。Driver 自动注入这些字段,但你得确保:
- 每次事务都复用同一个
session对象,不能在不同 session 间混用操作 - 事务内所有集合操作(
insertOne、updateMany等)都显式传入session参数,漏传 = 脱离事务上下文 - 单节点测试时,必须启动为副本集模式(哪怕只有一台),否则
startTransaction()会直接报错CommandNotSupportedOnServer
副本集 vs 分片集群:事务协议完全不同
副本集(4.0+)不走传统两阶段提交,而是靠 WiredTiger 的快照隔离 + oplog 多数派写入达成一致性;分片集群(4.2+)才真正启用两阶段提交,由协调分片(shard router)发起准备/提交流程。这意味着:
- 跨分片事务必然有更高延迟,且受
maxTransactionLockRequestTimeoutMillis(默认 5 秒)限制,超时直接中止 - 分片键必须出现在所有涉及的查询条件中,否则事务会因无法路由而失败,错误类似
TransactionNumbers do not match - 读操作若用
readConcern: "local",可能看到部分分片已提交、另一些尚未同步的状态,这不是 bug,是设计使然
WiredTiger 和 Write Concern 决定事务能否真正持久
事务原子性靠 WiredTiger 的 WAL 日志保障,但持久性取决于 writeConcern 配置。默认 {w: 1} 只写主节点,崩溃后可能丢失;生产环境必须设为 {w: "majority"},否则 commitTransaction() 返回成功 ≠ 数据已落盘。
-
writeConcern必须在startTransaction()前通过startTransaction({writeConcern: {w: "majority"}})显式声明,事务内无法动态修改 - 若副本集节点数为偶数(如 2 节点),
"majority"实际等价于w: 2,一旦一个节点宕机,事务会永久阻塞在 prepare 阶段 - WiredTiger 引擎不可替换——使用 MMAPv1 或内存引擎时,
startTransaction()直接不可用
最容易被忽略的隐性约束
事务不是万能胶。很多看似合理的操作会在运行时报错,而且错误信息极其模糊:
- 事务内不能创建/删除集合或索引,会触发
CommandNotSupportedInTransaction - 聚合管道中若含
$out或$merge,即使目标集合已存在,也会被拒绝 - 事务最大持续时间默认 60 秒,超时自动 abort,但不会抛异常——需主动检查
session.transaction.state是否为"ABORTED" - 嵌套事务不被支持,
session.startTransaction()在已有活跃事务时会报NoSuchTransaction
真正卡住人的从来不是语法,而是事务生命周期与集群状态、存储引擎行为、网络分区之间的耦合。写之前先确认 db.runCommand({replSetGetStatus: 1}) 和 db.serverStatus().storageEngine,比反复试错高效得多。


















