虽然,我们通常建议涉及到事务的情况下,不要在一个微服务里,调用另外一个微服务,但有时也会遇到无法避开的情况,那我们就来看看应该如何保证事务的一致性。

我们先来看看微服务A调用微服务B的伪代码:

//微服务A使用的数据库对象是 DbContextA

using var db = new DbContextA();
using var client = new JMS.RemoteClient();

//获取服务B对象
var serviceB = client.TryGetMicroService<ServiceB>();

//进行一系列数据库操作
db.xxx  

//调用服务B方法
serviceB.UpdateSomething();

//提交数据库事务
db.Commit();

//提交服务B事务
client.CommitTransaction();

在服务A里,进行了一系列数据库的操作,然后调用了服务B的方法,最后提交数据库事务和服务B的事务。

这段代码看着没啥问题,事务好像也是一起提交了。

但是,有种情况,如果数据库事务提交成功后,服务器宕机了,那服务B的事务就没有提交,这样事务的一致性就出问题了。

总结一下,如果你的代码有两个或以上Commit动作,那是无法保证事务一致性的。

那如何保证事务的一致性呢?

其实我们可以参考一下我们微服务框架对外的入口:webapi程序,它就可以同时调用多个微服务,并保证事务的一致性。

所以,依葫芦画瓢,服务A只要用RemoteClient,同时调用服务A和服务B,就可以保证事务的一致性。

那么,我们先把服务A的数据库操作,封装成一个微服务方法,大概如此:

    public class ServiceAController : MicroServiceControllerBase
    {
        public void ExecSomething()
        {
            var db = this.CurrentDBContext;
            db.BeginTransaction();

            .... //进行一系列数据库操作
        }
    }

然后,在服务A刚才运行业务功能的地方,用RemoteClient,同时调用自己和服务B

using var client = new JMS.RemoteClient();
var serviceA = client.TryGetMicroService<ServiceA>();
var serviceB = client.TryGetMicroService<ServiceB>();

//调用服务A的方法
serviceA.ExecSomething();

//调用服务B的方法
serviceB.UpdateSomething();

//提交所有事务
client.CommitTransaction();

这样,就实现了事务的一致性。