1. 课程导入与事务全景

在关系型数据库的世界里,事务几乎是默认能力:BEGIN、COMMIT、ROLLBACK 是每个开发者最早接触的语句之一。而 MongoDB 的成长路径不同——它最初以“文档模型 + 水平扩展”为核心卖点,原子性保证只落在单个文档内部。理解这条演进路线,是掌握 MongoDB 事务与一致性工程的第一步,也是本课程后续所有内容的坐标系。

一、MongoDB 事务能力的演进脉络

MongoDB 的原子性边界经历了三个清晰阶段。第一阶段是单文档原子性:对单个文档的更新,无论涉及多少个字段、多少层嵌套数组,MongoDB 都保证“要么全部生效,要么全部不生效”。这一保证从早期版本就存在,也是文档模型能够承载大量业务的基础。

第二阶段是复制集多文档事务。从 4.0 版本开始,MongoDB 在副本集(Replica Set)上支持多文档事务,事务可以跨多个集合、多个文档,甚至跨多个数据库。其底层依赖 WiredTiger 存储引擎的快照隔离(Snapshot Isolation)与副本集的 oplog 复制机制。

第三阶段是分片集群分布式事务。4.2 版本把事务能力扩展到分片集群(Sharded Cluster),事务可以跨分片执行,由 mongos 协调、各分片本地执行,并通过两阶段提交(2PC)保证跨分片一致性。至此,MongoDB 具备了与关系型数据库对标的 ACID 事务能力,但代价、限制与适用场景与单机关系库并不相同。

MongoDB 原子性边界的三级演进 原子性范围逐级扩大,协调成本与限制同步上升 ① 单文档原子性 版本:早期至今 一个文档 { _id, 字段, 嵌套数组 } 全部字段一起生效/失败 保证:文档级 ACID 无需显式事务 性能开销最低 ② 副本集多文档事务 版本:4.0 起 跨集合 / 跨文档 / 跨库 WiredTiger 快照隔离 oplog 复制保证持久 保证:多文档 ACID 需显式 session 事务 默认 60s 事务超时 ③ 分片集群分布式事务 版本:4.2 起 跨分片 / 跨 mongos mongos 协调 + 2PC 各分片本地执行 保证:分布式 ACID 协调开销最高 需关注分片键与路由 扩展 扩展 原子性范围越大 → 协调节点越多 → 延迟与冲突概率越高,需按业务边界选择

二、单文档原子性:被低估的工程基石

很多开发者把“MongoDB 不支持事务”当作旧印象,却忽略了单文档原子性本身就能解决大量问题。关键在于文档模型允许把强关联的数据内嵌到同一个文档中。例如一个订单文档:

{
  _id: ObjectId("..."),
  orderNo: "SO20240517001",
  status: "CREATED",
  items: [
    { sku: "A100", qty: 2, price: 39.9 },
    { sku: "B200", qty: 1, price: 128.0 }
  ],
  totalAmount: 207.8,
  createdAt: ISODate("2024-05-17T10:00:00Z")
}

当业务需要“扣减库存并写入订单明细”时,如果把明细内嵌在订单文档里,一次 updateOne 就能同时修改 items 与 totalAmount,天然具备原子性,无需事务。这就是文档建模优先原则:能用单文档原子性解决的,不要引入多文档事务。

判断标准:如果两个数据在业务上总是同时读写、生命周期一致、数量有界,优先内嵌到同一文档;只有当它们需要独立查询、独立增长或跨实体引用时,才考虑拆分并使用多文档事务。

三、多文档事务的边界与代价

多文档事务并非“免费午餐”。它带来四类必须正视的边界:

  • 超时限制:事务默认 transactionLifetimeLimitSeconds = 60 秒,超时会被服务端中止。长事务会持有快照与锁资源,必须拆短。
  • 锁与冲突:WiredTiger 使用文档级写冲突检测,两个事务修改同一文档时,后到者会收到 WriteConflict,需要应用层重试。
  • 快照隔离而非串行化:默认读已提交语义下可能出现写偏斜(Write Skew),需要显式读关注或唯一索引约束来兜底。
  • 分片事务的额外成本:跨分片事务需要 2PC,协调开销显著,且分片键选择不当会导致事务路由到多个分片。

四、一致性工程的核心挑战

事务只是工具,一致性才是目标。工程实践中真正的挑战来自三个层面:

读关注(readConcern)与写关注(writeConcern)的组合决定了一致性强度与性能的平衡。例如 readConcern: "majority" 配合 writeConcern: { w: "majority" } 可以避免读到回滚数据,但延迟更高;而 readConcern: "local" 性能好,却可能读到尚未被多数节点确认的数据。

因果一致性:在副本集读写分离场景下,客户端可能从从节点读到旧数据。MongoDB 通过 afterClusterTime 与因果会话(Causal Consistency Session)保证“读到自己写”的语义,但需要应用显式传递 session。

跨系统一致性:当 MongoDB 与消息队列、缓存、关系库协同工作时,本地事务无法覆盖外部系统,需要借助 Outbox 模式、变更流(Change Stream)或补偿事务来达成最终一致。

常见误区:认为“开启事务就万事大吉”。实际上,事务只保证数据库内部的原子性与隔离性,无法解决跨系统一致性、幂等性与重试风暴问题。一致性工程必须把事务、重试、幂等、补偿作为一个整体来设计。

五、本课程学习路线

基于上述全景,本课程将按“能力—边界—工程化”的主线展开:先建立单文档原子性与多文档事务的准确认知,再深入副本集与分片集群的事务机制、读关注/写关注组合、因果一致性与冲突处理,最后落到真实工程场景——订单扣减、库存对账、跨系统 Outbox、变更流驱动的一致性补偿,以及事务性能调优与故障排查。学完本课程,你应当能够判断“什么时候该用事务、什么时候不该用”,并能为具体业务设计出可落地的一致性方案。