如何在Entity Framework Core 2.1中实现多数据库分布式事务?
解决EF Core 2.1中分布式事务报错“This platform does not support distributed transactions”的问题
这个报错我之前也碰到过,主要是EF Core 2.1对分布式事务的支持有不少限制,结合你的场景,给你几个可行的解决方向:
先搞清楚报错的根本原因
EF Core 2.1里用TransactionScope做分布式事务,依赖的是系统级的分布式事务协调器(比如Windows上的MSDTC),而且不同数据库、不同运行平台的支持情况差异很大:
- 非Windows平台(Linux/macOS)基本不支持MSDTC,直接用
TransactionScope跨数据库肯定报错 - 就算是Windows,SQL Server需要正确配置MSDTC,而像MySQL、PostgreSQL这类数据库的EF Core驱动在2.1版本里大多不支持分布式事务
具体解决办法
1. 如果你用的是Windows+SQL Server,先配置MSDTC
如果你的两个上下文连接的都是SQL Server,且运行在Windows上,可以试试开启并配置MSDTC:
- 打开「服务」,找到「Distributed Transaction Coordinator」,确保服务处于启动状态
- 打开「组件服务」→「计算机」→「我的电脑」→「分布式事务协调器」→「本地DTC」,右键属性:
- 切换到「安全」选项卡,勾选「允许网络访问」「允许远程客户端」「允许出站」「允许入站」(根据你的环境调整,至少要允许网络访问)
- 重启MSDTC服务
不过这种方式局限性很大,一旦跨平台或者换数据库就失效,而且配置起来容易踩坑。
2. 同一数据库实例下,共享连接实现事务
如果你的TestDBContext和TestDB2Context连接的是同一个SQL Server实例(哪怕是不同数据库),可以用共享数据库连接的方式替代TransactionScope,不需要依赖MSDTC:
try { // 共用一个数据库连接 using (var connection = new SqlConnection("你的主连接字符串")) { connection.Open(); // 开启本地事务 using (var transaction = connection.BeginTransaction()) { // 让两个上下文共用这个连接和事务 var ctx1Options = new DbContextOptionsBuilder<TestDBContext>() .UseSqlServer(connection) .Options; var ctx2Options = new DbContextOptionsBuilder<TestDB2Context>() .UseSqlServer(connection) .Options; using (var ctx1 = new TestDBContext(ctx1Options)) using (var ctx2 = new TestDB2Context(ctx2Options)) { ctx1.Database.UseTransaction(transaction); ctx2.Database.UseTransaction(transaction); ctx1.Person.Add(new Person { Name = "piran" }); ctx2.Course.Add(new Course { Name = "C#" }); ctx1.SaveChanges(); ctx2.SaveChanges(); } // 提交事务 transaction.Commit(); } } } catch(Exception ex) { Debug.WriteLine(ex.Message); }
3. 跨数据库/平台?用Saga模式实现最终一致性
如果是真正的跨不同数据库实例(比如SQL Server+MySQL),或者运行在Linux/macOS上,TransactionScope的强一致性分布式事务基本走不通,这时候得换「最终一致性」的思路,也就是Saga模式:
把每个数据库的操作拆成独立的本地事务,一旦某个步骤失败,就执行对应的补偿操作回滚之前的变更。示例代码大概是这样:
bool personAdded = false; bool courseAdded = false; try { // 第一步:操作第一个数据库 using (var ctx1 = new TestDBContext()) { ctx1.Person.Add(new Person { Name = "piran" }); ctx1.SaveChanges(); personAdded = true; } // 第二步:操作第二个数据库 using (var ctx2 = new TestDB2Context()) { ctx2.Course.Add(new Course { Name = "C#" }); ctx2.SaveChanges(); courseAdded = true; } } catch(Exception ex) { Debug.WriteLine($"执行失败:{ex.Message}"); // 补偿操作:回滚已完成的变更 if (personAdded) { using (var ctx1 = new TestDBContext()) { var person = ctx1.Person.FirstOrDefault(p => p.Name == "piran"); if (person != null) { ctx1.Person.Remove(person); ctx1.SaveChanges(); } } } if (courseAdded) { using (var ctx2 = new TestDB2Context()) { var course = ctx2.Course.FirstOrDefault(c => c.Name == "C#"); if (course != null) { ctx2.Course.Remove(course); ctx2.SaveChanges(); } } } }
这种方式虽然不是实时的强一致,但能保证最终数据是一致的,是跨分布式场景下的常用方案。
4. 升级EF Core版本(推荐)
EF Core 2.1确实比较老了,3.0及以上版本对分布式事务的支持有了明显改进:
- Windows上SQL Server的
TransactionScope支持更稳定 - 部分数据库驱动(比如Npgsql for PostgreSQL)也开始支持分布式事务
如果项目允许的话,升级到EF Core 3.1或者更高的LTS版本,能省不少麻烦。
内容的提问来源于stack exchange,提问作者Babak Golkar




