MongoDB 4.0 多文档事务深度复用 WiredTiger 原生 MVCC 与快照机制,事务启动时获取 clusterTime 快照,读操作基于该时间点视图,写冲突仅在 commit 阶段检测;oplog 异步刷盘,需启用 journal 并设短超时以保障 durability。
MongoDB 4.0 的多文档事务不是在存储引擎层之上“额外叠加”的逻辑,而是深度复用 WiredTiger(WT)原生的多行事务能力 —— 它本质上是把 WT 单行事务的封装粒度从“一次 updateOne”放大到“一个 session 内所有操作”,底层仍由 WT 的快照与 MVCC 机制驱动。
MongoDB 不自己维护版本链或 undo log,而是依赖 WT 引擎的内部快照机制:每个事务启动时获取一个全局单调递增的 clusterTime,后续所有读操作都基于该时间点的已提交数据视图。这意味着:
find() 看到的是同一份快照,不会出现不可重复读commitTransaction() 阶段检测:若另一事务已修改同一文档且其 txnNumber 更高,则当前事务抛 WriteConflict
readConcern: "snapshot" 是事务默认值,但普通非事务读即使显式设置该值,也不会绑定到事务快照 —— 它只对事务内操作生效startTransaction() 只是配置会话状态(如 writeConcern、readConcern、超时参数),并不真正开启底层 WT 事务。真正的事务生命周期绑定在 session 对象上 —— 从 startSession() 创建起,到 commitTransaction() 或 abortTransaction() 结束,整个过程对应 WT 层一个 WT_SESSION 的 write unit。这也解释了为什么:
session 不能并发执行多个事务(会报 IllegalOperation)session 参数,否则不被纳入事务上下文with_transaction() 是语法糖,本质仍是显式管理 session.start_transaction() 和 session.commit_transaction()
事务提交成功 ≠ oplog 已落盘。WiredTiger 先将变更写入内存并打上 clusterTime 标记,commitTransaction() 返回后才异步刷入 oplog。这带来两个关键事实:
journal: true 并配置足够小的 transactionLifetimeLimitSeconds(建议 ≤30)commitTransaction() 成功响应后,仍需检查返回的 ok: 1 和 operationTime,不能仅靠异常捕获判断结果;超时后服务端自动 abort,但客户端可能收不到明确错误applyOps 命令批量重放,因此分片集群中跨分片事务无法协调 —— 这就是 4.0 不支持跨分片事务的根本原因真正容易被忽略的是:事务快照的可见性窗口和 oplog 刷盘延迟之间存在时间差,极端网络分区或节点故障下,可能短暂观察到“已提交又消失”的幻读现象。这不是 bug,而是快照隔离 + 异步日志的固有 trade-off。