基于Spring事务扩展
有些情况下,Spring事务会失效,比如我们在方法内部调用这个类的方法,那我们基于注解的Spring事务就会失效,因为我们在方法内使用的this 进行调用,而没有使用Spring提供的代理对象
还有我们使用异步处理时,由于Spring事务只存在于主线程中,我们采用异步的方式,是没办法用Spring事务的。
我们在本地事务执行完发送一条MQ,此时发送MQ的动作如果在方法内部,那么事务还没有提交,我们就已经发送了消息,如果事务回滚,消息无法撤回。
如果将send MQ放在方法外执行,又可能出现事务提交后宕机,MQ没来及执行的情况。
那么如何保证我们的事务和MQ的一致性呢?
这里用到了Spring事务的事务同步器的一个知识点,
首先写一个事务扩展点:
//SPI(Service Provider Interface) 写Spring 事务的扩展点 class DoaTransactionCompletion implements TransactionSynchronization { private Runnable runnable; //用构造方法把Runnable 传进来 public DoaTransactionCompletion(Runnable runnable) { this.runnable = runnable; } @Override public void afterCompletion(int status) { //判断事务是否可以提交 if (status == TransactionSynchronization.STATUS_COMMITTED) { //提交了就让他执行下面内容 this.runnable.run(); } } }
然后我们写一个静态的工具类,封装我们想要干的事情:
public static void doAfterTransaction(DoaTransactionCompletion doafterTransaction){ //检查当前是否包含事务 if(TransactionSynchronizationManager.isActualTransactionActive()){ //将我们的Spring事务扩展点注册进事务同步器中 TransactionSynchronizationManager.registerSynchronization(doafterTransaction); } }
下面演示一下如何使用这个:
@Transactional void doTx(){ // 开启事务 TransactionUtil.doAfterTransaction(new DoaTransactionCompletion(()->{ //send MQ.....RPC... })); //结束事务 }
@Transactional 开启Spring注解事务,使用我们的写好的静态方法,方法里需要一个 DoaTransactionCompletion 对象,我们有一个带Runable的构造器,所以我们需要将我们内容也写出来。
等事务执行完可以提交时,会回调我们事务同步器里的方法发送MQ。