基于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。

 

posted @ 2022-12-12 22:21  kisshappyboy  阅读(84)  评论(0编辑  收藏  举报