mongodb 4.0事务必须同时满足副本集部署、wiredtiger引擎和显式会话三者,缺一则报错或静默降级;单机模式不支持,分片集群事务需4.2+,且事务内操作须同属一副本集、限60秒、隔离级别固定为snapshot。

MongoDB 4.0 副本集事务不是“开箱即用”,必须满足副本集拓扑、WiredTiger 引擎、会话机制三者齐备,缺一不可;否则 session.startTransaction() 会直接报错或静默降级为非事务操作。
副本集是硬性前提,单机或分片集群不适用
事务在 MongoDB 4.0 中仅支持副本集(replica set),不支持单机部署或分片集群(分片事务要等到 4.2)。常见错误现象是本地开发时直接启动 mongod --port 27017,然后调用 s.startTransaction() 却抛出 CommandNotSupported: Transactions are not supported on standalone servers。
验证方式很简单:连接后执行 rs.status(),返回中必须有 members 数组且至少含 3 个节点(推荐 1 主 2 从),ok: 1,且无 errmsg。若提示 not master 或 no replset config,说明副本集未初始化。
- 初始化只需一次:
rs.initiate({ _id: "rs0", members: [{ _id: 0, host: "localhost:27017" }] }) - 添加成员用
rs.add("localhost:27018"),不要用 IP+端口混搭(如127.0.0.1:27017和localhost:27017被视为不同节点) - 所有节点必须使用 WiredTiger 存储引擎(默认),MMAPv1 已被完全弃用,无法开启事务
事务生命周期绑定 Session,不能跨连接复用
每个事务必须由一个显式创建的 ClientSession 实例承载,db.getMongo().startSession() 返回的对象不可复用,也不能从连接池里“捞出”旧 session 续用。常见误用是把 session 存成全局变量或静态字段,导致后续事务实际运行在无上下文的默认会话中,ACID 保障失效。
正确做法是:每次业务逻辑开始前新建 session,结束时显式 commitTransaction() 或 abortTransaction()。不调用 commit 也不 abort,session 会在 60 秒后自动过期(可配 transactionLifetimeLimitSeconds),但期间占用服务器资源。
- shell 示例中
s = db.getMongo().startSession()必须紧跟s.startTransaction(),中间不能插入其他非事务命令 - Driver 中(如 Java/Python)需确保
with session.start_transaction():或 try-finally 结构包裹全部操作 - Spring Data MongoDB 的
@Transactional底层仍依赖MongoTransactionManager创建并绑定 session,若配置漏掉transactionEnabled: true或MongoTransactionManagerBean 未注册,注解将完全无效
ACID 在副本集中的落地方式与限制
MongoDB 不走传统两阶段提交(2PC),而是靠 oplog + Raft 日志复制 + WiredTiger MVCC 快照实现 ACID。这意味着事务提交成功,只代表主节点已写入 oplog 并获得多数派确认,而非所有副本都完成应用——但读操作默认使用 readConcern: "majority",因此不会读到未提交或回滚的数据。
关键限制点常被忽略:
- 事务内不能执行
listCollections、createIndex等部分管理命令(DDL 有限支持从 4.4 才开始) - 事务最大持续时间默认 60 秒,超时自动 abort,可通过
maxTransactionTimeMS参数调整,但不建议设过高——长事务会阻塞 oplog 截断,拖慢整个副本集 - 事务内所有操作必须落在同一副本集内,不能跨分片、不能跨 mongos、不能访问其他集群的数据库
- 隔离级别固定为 snapshot(快照隔离),不支持
readUncommitted或repeatableRead等自定义级别
真正容易踩坑的是“事务看似成功,但下游读不到最新值”——这往往是因为客户端没设 readConcern: "majority",或者用了过时的驱动版本(如 pymongo











