MongoDB事务默认且唯一支持Read Committed隔离级别,实际行为接近快照隔离,具备读己所写和事务内一致性快照能力,但不防止幻读,也不支持可序列化或未提交读。

MongoDB事务默认用的是“可重复读”隔离级别
结论很直接:MongoDB 4.0+ 的多文档事务,默认且**唯一支持的隔离级别是 Read Committed(已提交读)**,但它的实际行为更接近“快照隔离(Snapshot Isolation)”,在绝大多数场景下表现等价于可重复读(Repeatable Read)。这不是 ANSI SQL 意义上的可重复读,但官方文档和内核实现都明确将其归类为 Read Committed,同时具备 Read Your Own Write 和事务内一致性快照能力。
为什么不是“可序列化”或“未提交读”
MongoDB 不支持 ANSI 定义的 Serializable 或 Read Uncommitted 隔离级别。它不提供范围锁(range lock),所以无法彻底防止幻读;也不允许脏读——任何未提交事务写入的数据,对其他事务完全不可见,哪怕加了 readConcern: "local" 也不行。
-
readConcern: "local"只影响非事务性读取,对事务内读无效;事务内强制使用readConcern: "snapshot"(自动启用) - 试图在事务中手动设置
readConcern: "majority"或"available"会报错:read concern is not supported in transactions - 没有
SET TRANSACTION ISOLATION LEVEL这类 SQL 语句,隔离级别由引擎硬编码决定,不可配置
事务内读操作的真实行为:快照 + 自己写的马上可见
你在事务里第一次写入一条文档,紧接着执行 find(),哪怕事务还没 commitTransaction(),也能查到刚写的那条——这就是 Read Your Own Write。但其他并发事务此时完全看不到它,直到你提交。
- 事务开始时,WiredTiger 会基于当前
oplog时间戳建立一个一致性的数据快照 - 整个事务生命周期内所有读都基于这个快照,不会被其他事务的中间提交干扰
- 幻读仍可能发生:比如事务 A 先查
{ status: "pending" }得到 5 条,事务 B 插入一条新 pending 文档并提交,事务 A 再查可能变成 6 条 - 这不是 bug,是 Snapshot Isolation 的固有特性,MongoDB 明确文档指出“不保证防止幻读”
容易踩的坑:误以为能跨事务控制隔离级别
很多开发者想通过 readPreference 或 readConcern 在事务里调高隔离强度,结果发现全被忽略。事务的隔离机制是底层存储引擎(WiredTiger)和复制协议共同保障的,上层驱动和 shell 命令无权覆盖。
- 在
session.startTransaction()后调用coll.find().readConcern("majority")不生效,驱动会静默丢弃 - 分片集群中,事务必须路由到同一分片(或通过
shard key精确定位),否则直接报TransactionNotSupportedOnShardedCluster - 集合没启
writeConcern: { w: "majority" },事务提交后可能因主节点宕机丢失——这不是隔离问题,但常被混淆
真正需要强一致性的场景(比如金融对账),得靠应用层加锁、业务逻辑规避,或者用单文档原子更新替代多文档事务。MongoDB 的事务设计本就偏向“够用、轻量、不阻塞”,别把它当 PostgreSQL 使。










