C#操作MongoDB事务回滚失效的原因及解决方法
问题根因
事务未生效的核心原因是你执行写操作时没有将当前事务会话绑定到操作上。
MongoDB C# 驱动不会自动把当前上下文里启动了事务的session关联到后续的CRUD操作,所有需要纳入事务的读写操作,都必须显式传入对应的session对象,否则操作会直接走独立的自动提交连接,完全不受你启动的事务控制——这也是为什么抛异常后没提交事务,第一条插入的数据还是落库了:这条InsertOne根本没跑在你开的事务里。
修正方案
- 所有需要加入事务的CRUD操作,第一个参数传入当前事务session对象
- 增加异常捕获逻辑,出错时显式回滚事务,避免资源泄漏
- 注意:MongoDB多文档事务仅支持副本集、分片集群部署,单节点mongod实例无法正常运行事务。
修正后的完整代码:
var mongoClient = new MongoClient("connection-bla-bla"); var mongoDB = mongoClient.GetDatabase("db-name"); using (var session = mongoDB.Client.StartSession()) { try { session.StartTransaction(); var collection = mongoDB.GetCollection<Rec>("collectionName"); // 第一个参数传入当前事务session,将操作绑定到事务 collection.InsertOne(session, new Rec() { Name = "Record1" }); if (DateTime.UtcNow > DateTime.MinValue) throw new Exception("Bad things happens"); collection.InsertOne(session, new Rec() { Name = "Record2" }); session.CommitTransaction(); } catch (Exception ex) { // 捕获异常时主动回滚事务 session.AbortTransaction(); // 可在此处添加自定义异常处理逻辑 throw; } }
额外说明
- 只要是事务内的操作,不管是增删改查、聚合,都需要把session作为第一个参数传入对应方法重载,否则都不会被事务管控
- 不手动调用
AbortTransaction的话,session被using释放时也会尝试终止未提交的事务,但显式在catch块里调用回滚逻辑更可控,方便排查问题
内容的提问来源于stack exchange,提问作者user1470240
相关产品推荐
相关产品推荐

