You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在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. 同一数据库实例下,共享连接实现事务

如果你的TestDBContextTestDB2Context连接的是同一个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

火山引擎 最新活动