MongoDB多文档事务仅支持WiredTiger引擎和副本集部署,需驱动v1.4.0+、显式传session、正确连接参数,且禁用非数据库操作;单点、MMAPv1或配置缺失均导致事务不可用。

WiredTiger 是硬性前提,MMAPv1 或其他引擎直接不支持事务
MongoDB 4.0+ 的多文档事务**只在 WiredTiger 存储引擎下可用**,这是由底层锁粒度和快照隔离机制决定的。MMAPv1、In-Memory 引擎等都不支持事务——哪怕你用的是 4.2 或 5.0 版本,只要 storage.engine 不是 wiredTiger,调用 startTransaction() 就会报错:Transaction numbers are only allowed on a replica set member 或更直白的 Transactions are not supported。
- 检查方式:连接后执行
db.serverStatus().storageEngine.name,必须返回"wiredTiger" - 默认值:MongoDB 3.2+ 新建实例已默认使用 WiredTiger;但升级旧实例(如从 3.0 MMAPv1 升级)不会自动切换,需手动迁移
- 无法绕过:不能通过配置参数或驱动降级来“启用”非 WiredTiger 上的事务
单点部署(Standalone)无法开启事务,必须是副本集
事务功能依赖 MongoDB 内部的 oplog 和多数派写入机制,因此**强制要求运行在副本集(Replica Set)模式下**。哪怕你只启一个节点(mongod --replSet rs0),也必须初始化副本集(rs.initiate()),否则 session.startTransaction() 会直接 panic 或抛出 Transaction numbers are only allowed on a replica set member。
- 常见误操作:本地开发时用
mongod --port 27017启单点,以为加了?retryWrites=true就能跑事务 → 实际完全无效 - 最小可行配置:单节点副本集即可满足事务要求,不需要真正多个物理节点
- 分片集群也支持事务,但需注意跨分片事务有额外限制(如不能在事务中创建新集合)
驱动版本和连接参数不匹配,会导致事务静默失效
Go 驱动(mongo-go-driver)对事务的支持高度依赖客户端与服务端协议协同。如果驱动太老或连接字符串漏关键参数,事务看似能启动,但实际退化为普通写入——没有原子性、不回滚、也不报错。
- 必须使用
go.mongodb.org/mongo-driver/mongov1.4.0+(对应 MongoDB 4.0+);v1.0.x 默认禁用事务上下文传递 - 连接字符串里必须显式加上
?replicaSet=rs0(匹配你的副本集名),否则驱动不会启用 session 支持 -
retryWrites=true要设为true(默认值),但注意:某些错误场景下它反而干扰事务控制,遇到TransientTransactionError时应按官方推荐逻辑重试,而非依赖自动 retry - 事务内所有操作(如
collection.InsertOne(session, doc))必须显式传入session,漏传就等于没进事务
事务不是万能的,设计不当反而放大风险
WiredTiger 虽支持文档级锁,但事务期间仍会持有快照、占用内存、延长 oplog 生命周期。尤其当事务里混入长耗时操作(如大数组遍历、外部 HTTP 调用)、或读写量过大(>1000 文档/事务),极易触发 MaxTimeMSExpired 或 oplog 截断失败。
- 事务默认超时 60 秒,可通过
session.StartTransaction(&options.TransactionOptions{MaxCommitTime: 30 * time.Second})调整,但治标不治本 - 避免在事务中做非数据库操作(比如发消息、调第三方 API),这些失败无法被 MongoDB 回滚
- 优先考虑单文档建模:用嵌入数组、引用 ID + 应用层补偿,比强上分布式事务更稳、更快
- 事务日志(oplog)体积会显著增长,确保
oplogSizeMB足够(副本集默认 5% 磁盘空间,但高事务负载建议手动设为 ≥2048)
事务真正的门槛不在语法,而在部署形态和引擎绑定——没开副本集、没用 WiredTiger、驱动连不上正确拓扑,代码写得再标准也没用。这些条件缺一不可,且没法靠“试试看”发现,必须逐项验证。

















