mongodb 事务必须使用 iclientsession + starttransaction(),严禁混用 ef core 的 idbcontexttransaction;需显式 await abort/commit 并处理异常,session.dispose() 不会自动回滚事务。

IDbContextTransaction 不适用于 MongoDB
MongoDB 事务和 EF Core 的 IDbContextTransaction 完全不兼容。EF Core 是为关系型数据库设计的抽象层,而 MongoDB 驱动使用的是原生会话(IClientSession)+ 显式事务控制。强行混用会导致事务上下文丢失、操作静默失败,甚至数据不一致。如果你在代码里看到 DbContext.Database.CurrentTransaction 或调用了 BeginTransaction(),那它对 MongoDB 根本无效——MongoDB 驱动压根不认这个。
必须改用 IClientSession + StartTransaction() 流程,且所有集合操作都得显式传入该 session 实例。
事务回滚不等于业务失败通知
MongoDB 驱动的 session.AbortTransactionAsync() 和 session.CommitTransactionAsync() 都是纯异步操作,成功或失败都只反映数据库侧状态,不会自动中断 C# 执行流。常见错误是:
- 在
catch块中只调用session.AbortTransactionAsync(),没await也没throw - 调用
AbortTransactionAsync()后继续执行后续逻辑(比如返回 success = true) - 误以为
using (var session = client.StartSession())能兜底回滚——其实 session.Dispose() 不会自动 abort 未提交事务,必须手动处理
正确做法是:捕获异常 → await session.AbortTransactionAsync() → 立即 throw 或 return 错误结果。否则上层服务可能把“已回滚”当成“操作成功”。
session 生命周期与连接稳定性强绑定
MongoDB 事务的有效性极度依赖 IClientSession 实例是否仍处于活跃状态,以及底层连接是否可用。几个关键事实:
-
session.StartTransaction()必须在连接打开后调用;若连接已断开(如网络抖动、超时踢出),会直接抛InvalidOperationException - 事务期间如果 session 被 dispose(例如 using 块提前退出),再调用
AbortTransactionAsync()会失败,报 “Session has been disposed” - 跨
async/await边界时,不能把 session 存在局部变量里然后扔进Task.Run——IClientSession不是线程安全的,也不支持上下文流转 - 事务内所有操作(
InsertOneAsync、UpdateManyAsync等)都必须带{ session }参数,漏一个就脱离事务范围
没有自动回滚兜底机制
这是最容易被忽略的一点:MongoDB 驱动不会在作用域结束时自动回滚未提交事务。不像 EF Core 的 DbContext 在 Dispose() 时尝试回滚(且有连接存活前提),MongoDB 的 IClientSession 的 Dispose() 只释放资源,完全不管事务状态。如果你写了这样的代码:
using (var session = client.StartSession())
{
session.StartTransaction();
await collection.InsertOneAsync(..., session);
// 忘了 Commit 或 Abort,也没有 try/catch
}
那么事务既没提交也没回滚,session 关闭后连接可能复用,但这次事务已“悬空”,数据库行为不可预测——某些情况下会被服务器端超时清理,但不保证原子性,也不触发任何 .NET 异常。必须显式控制流程分支,每个出口都要覆盖 Commit 或 Abort。











