Spring Data MongoDB 的 @Transactional 不支持设置隔离级别,实际仅快照隔离有效,且仅 transactionManager 和 propagation 参数生效,其余如 isolation、timeout、readOnly 等效果有限或被静默忽略。

Spring Data MongoDB 的 @Transactional 不支持设置隔离级别。 你写 @Transactional(isolation = Isolation.REPEATABLE_READ) 是无效的,MongoDB 驱动会忽略它,也不会报错 —— 这是容易被误以为“配置成功”的关键陷阱。
为什么 MongoDB 事务不接受 isolation 参数
MongoDB 自身的事务模型(自 4.0 副本集、4.2 分片集群起)只提供一种事务语义:快照隔离(Snapshot Isolation),它比 SQL 标准中的 REPEATABLE_READ 更强,能防止幻读,但不是可序列化(SERIALIZABLE)。Spring 的 isolation 枚举是为 JDBC 设计的,MongoDB 事务管理器 MongoTransactionManager 并未实现对这些值的映射或校验。
- 调用
@Transactional(isolation = Isolation.READ_COMMITTED)不会改变行为,实际仍是快照隔离 - 传入
Isolation.SERIALIZABLE也不会触发额外锁或串行化执行,MongoDB 本身不支持该级别 - Spring 在启动时不会报错,因为
MongoTransactionManager继承自抽象基类,isolation属性被静默丢弃
真正起作用的只有 transactionManager 和 propagation
在 MongoDB 场景下,@Transactional 中唯一生效的参数是 transactionManager 和 propagation。其他如 timeout、readOnly 虽然会被识别,但效果有限:
-
transactionManager必须显式指定为@Transactional(transactionManager = "mongoTransactionManager"),否则默认走 JPA 的DataSourceTransactionManager -
propagation = Propagation.REQUIRED(默认)和Propagation.REQUIRES_NEW是唯一影响事务边界的传播行为;NESTED在 MongoDB 中无意义,不被支持 -
readOnly = true仅作为提示,MongoDB 驱动不会因此跳过写锁或禁用日志,实际仍可能写入 oplog -
timeout会被传递给ClientSession.startTransaction(),但超时由 MongoDB 服务端控制,精度有限(秒级)
事务生效的前提条件必须全部满足
即使注解写对了,MongoDB 事务也极易因环境或用法问题而“静默降级”为非事务执行:
- 必须运行在副本集(Replica Set)或分片集群(Sharded Cluster)上;单节点
mongod不支持事务 -
MongoTransactionManager的构造参数必须是MongoDatabaseFactory,不能是旧版MongoDbFactory或直接传MongoTemplate - 事务内只能使用
MongoTemplate,不能混用MongoRepository—— 后者底层不参与当前ClientSession - 所有操作必须发生在同一个
MongoTemplate实例上,且该实例与MongoTransactionManager共享同一MongoDatabaseFactory
最常被忽略的一点:事务边界外的读操作(比如事务中调用另一个 service 方法,而它没加 @Transactional)会使用独立 session,看不到事务内未提交的变更 —— 这不是隔离级别问题,而是 session 隔离本身导致的,和 isolation 参数完全无关。











