MongoDB 4.0+ 多文档事务仅支持副本集或分片集群,不支持单节点;必须同库、非跨库操作;需显式配置 readConcern: "snapshot" 和 writeConcern: { w: "majority" } 才具备 ACID 保证。

MongoDB 4.0+ 的多文档事务能解决跨集合一致性,但必须在副本集或分片集群上启用,并且不能跨数据库。两阶段提交是旧版 workaround,现在基本不该用。
事务要求:必须是副本集或分片集群
MongoDB 的 session.startTransaction() 只在副本集(replica set)或分片集群(sharded cluster)中可用。单节点 standalone 模式不支持事务 —— 即使你调用了 startTransaction(),也会直接报错 CommandNotSupportedOnStandalone。
- 确认当前部署类型:
rs.status()(副本集)或sh.status()(分片集群) - standalone 实例想用事务?只能升级为副本集(至少 3 节点,或 1 主 + 2 arbiter)
- 事务日志(oplog)依赖副本集机制,这是底层硬约束,绕不开
事务限制:不能跨数据库,且集合需在同一分片(如适用)
一个事务内可以操作多个集合,但所有集合必须属于同一个数据库(db)。跨 db.products 和 db.orders 是非法的,会触发 InvalidNamespace 错误。
- 如果业务天然需要跨库操作(比如
auth库和billing库),只能拆成多个事务 + 外部补偿逻辑 - 在分片集群中,所有被事务读写的集合必须是“非分片集合”(即未启用
sh.enableSharding()),或确保它们的分片键完全一致且路由到同一分片 —— 否则报TransactionNotSupportedOnShardedCollection -
system.*集合、admin库中的集合、以及任何使用$lookup引用其他数据库的聚合管道,都不允许出现在事务中
两阶段提交(2PC)现在只是历史参考,别在新项目里实现
官方文档已明确将两阶段提交标记为“legacy pattern”。它靠应用层维护状态字段(如 status: "pending")、手动回滚/重试、定时扫描清理,极易出错且无法保证严格一致性。
- 典型失败场景:第二步写入失败后,第一步已提交却没回滚;或网络分区导致协调者失联,悬挂状态长期存在
- 没有原子性保障 —— 任意一步崩溃,都需要人工干预或复杂恢复脚本
- MongoDB 4.0 之后,只要满足前述部署和结构约束,直接用
session.commitTransaction()更安全、更简洁 - 如果你在维护老系统且仍用 2PC,请优先评估迁移到事务的可行性,而不是加固 2PC 流程
容易被忽略的关键点:读关注(readConcern)和写关注(writeConcern)必须显式设置
即使开了事务,如果没配对 readConcern: "snapshot" 和 writeConcern: { w: "majority" },你看到的“一致视图”可能只是幻觉。
-
readConcern: "local"(默认)下,事务内读取可能看到未提交的中间状态或其他并发事务的脏数据 -
writeConcern: { w: 1 }会让写入只落盘主节点就返回成功,一旦主节点宕机且未同步,事务就“消失”了 - 真实生产环境必须设为
readConcern: "snapshot"+writeConcern: { w: "majority" },否则事务的 ACID 保证不成立 - 这个配置不是全局默认值,每次启动 session 后都要在
startTransaction()调用中显式传入


















