在微服务内部,调用另一个微服务,如何保证事务的一致性
虽然,我们通常建议涉及到事务的情况下,不要在一个微服务里,调用另外一个微服务,但有时也会遇到无法避开的情况,那我们就来看看应该如何保证事务的一致性。
我们先来看看微服务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();
这样,就实现了事务的一致性。