MongoDB事务不会自动回滚,必须显式调用session.abortTransaction();否则会话长期处于open状态、占用资源、导致后续操作阻塞或报错。

MongoDB 事务不会自动回滚,必须显式调用 session.abortTransaction() —— 依赖超时或异常穿透都不安全。
事务失败后不调用 abortTransaction() 会发生什么
事务中任意操作抛出异常,但没在 catch 或 finally 里调用 session.abortTransaction(),会导致:
- 会话(
ClientSession)可能长期处于“进行中”状态,占用服务器资源 - 未提交的变更仍被暂存,直到会话超时(默认 60 秒),期间其他读操作若带
snapshot或readConcern: "snapshot"可能读到脏数据 - 同一会话后续再调用
commitTransaction()会直接报IllegalStateException,而abortTransaction()在已超时或已提交后调用也会失败
Java 驱动中手动 abort 的典型写法(同步版)
使用 MongoClient 同步驱动(如 4.11+)时,关键是在异常分支和资源清理路径上覆盖所有退出点:
ClientSession session = mongoClient.startSession();
try {
session.startTransaction();
collection.insertOne(doc1, new InsertOneOptions().session(session));
collection.updateOne(filter, update, new UpdateOptions().session(session));
// 业务校验失败 → 主动中止
if (!checkBusinessRule()) {
session.abortTransaction();
return;
}
session.commitTransaction();
} catch (Exception e) {
// 必须在这里 abort,不能只靠 finally
session.abortTransaction();
throw e;
} finally {
session.close(); // 注意:不是 endSession(),旧版驱动用 close()
}
注意:session.close() 是必需的,否则连接泄漏;abortTransaction() 可重复调用(幂等),但 commitTransaction() 成功后再调用会抛异常。
为什么不能依赖 try-with-resources 自动 abort
ClientSession 实现了 AutoCloseable,但它的 close() 方法不等于 abortTransaction():
- 驱动 ≥ 4.3 且使用
mongoClient.startSession()获取的 session,close()仅释放网络资源,不触发 abort - 事务仍处于 open 状态,直到超时或显式 abort
- 若误写成
try (ClientSession s = client.startSession()) { ... }而没手动 abort,等于放弃控制权
Spring Data MongoDB 的 @Transactional 不适用于原生事务回滚
Spring 的 @Transactional 注解对 MongoDB 仅在使用 MongoTransactionManager + MongoTemplate 时生效,它底层仍封装了 abortTransaction() 调用,但有严格前提:
- 必须启用
@EnableMongoRepositories并配置MongoTransactionManager - 方法必须是 public、非 final、由 Spring 代理调用(不能 this.method())
- 异常必须未被捕获(即向上抛出),且类型未被
rollbackFor排除 - 它不支持跨多个
MongoClient实例或混合 JDBC 操作的分布式事务
一旦你绕过 Spring 封装,直接用 mongoClient.startSession(),就彻底脱离了 Spring 事务管理器的控制范围 —— 此时 @Transactional 完全无效,回滚责任 100% 回归到你自己手上。











