美文网首页
Spring中解决事务以及异步注解失效

Spring中解决事务以及异步注解失效

作者: 守住阳光 | 来源:发表于2018-11-23 14:03 被阅读0次

    一、重现@Transaction失效的场景

            有如下业务场景,新增订单后,自动发送短信,下面的代码在同一个类中:

    @Transaction

    public void addOrder(OrderInfo  orderInfo){ 

            orderMapper.insert(orderInfo);

            try{

                    sendMesg(orderInfo );

            }cach(Exception e){

                    e.printStrace();

            }

    }

    @Transaction

    public void sendMesg( OrderInfo  orderInfo ){

            mesgMapper.insert(orderInfo );

            throws new RuntimeException("发送短信出现异常!");

    }

            上面的伪代码模拟新增订单后,自动发送短信的业务场景。两个操作被标识为事务,为了不影响发送短信出现异常影响订单的插入,在调用发送短信的方法时,通过 try....cach...捕获其异常并处理,不影响订单表的插入。

            因为sendMesg标识为事务,其抛出异常后,事务按正常逻辑来说,事务会进行回滚,即短信表中不会插入记录。然而事与愿违,出现的结果是短信表也插入了记录。

    二、重现异步注解失效的场景

    1、异步注解@Async介绍

            基于@Async标注的方法,称之为异步方法,这些方法在执行的时候,spring将会为其开辟独立的线程执行,调用者无需等待它的完成,即可继续其他的操作。

    2、如何使用@Async

            增加 aspectj 相关的依赖;

            修改 spring配置文件,在配置文件中增加如下配置:

            <task:annotation-driven executor = "annotationExecutor"  />

            <task:executor id="annotationExecutor" pool-size="20" />

            在方法上加上@Async注解。

    3、业务场景介绍

    预定旅游套餐业务场景

    @Transaction 

    public void planTourismPackages(Order orderInfo){

            dealPassengerTicketBusiness(orderInfo);

            dealHotelBusiness(orderInfo);

            sendMesg(orderInfo);

            sendEmial(orderInfo);

     }

    @Async

    public void sendMesg( OrderInfo  orderInfo ){

            mesgMapper.insert( orderInfo  );         

            throws new RuntimeException("发送短信出现异常!"); 

    }

            预定旅游套餐时,首先处理机票预定业务,然后处理酒店预定业务,最后发送短信个邮件。发送短信和邮件属于辅助业务,可以让其异步执行,所以在方法上加了@Async注解,让其异步执行。为了演示效果,我将planTourismPackages方法标识为事务处理,故意让sendMesg方法抛出异常。按我们预想,因为sendMesg方法异步执行,其抛出异常应该不会影响planTourismPackages事务的提交,机票预定表和酒店预定表应该会插入记录。但是,事与愿违,sendMesg抛出异常导致planTourismPackages事务会滚了,说明@Async并未生效。

    三、原因分析

            为什么会出现上面的事务和异步注解失效呢?

            spring声明式事务和异步注解的实现都是基于spring aop,即对标识的方法进行增强。spring aop的底层实现原理是 jdk 动态代理。因为事务注解方法,异步方法的调用的方法在同一个类中,所以发送短信方法是在调用方法的代理对象中执行的,没有对发送短信方法进行增强。如下图:

    orderMapper.insert( orderInfo );                                                     

    try{ 

             this.sendMesg( orderInfo  ); 

     }cach(Exception e){ 

            e.printStrace();   

     } 

    public void planTourismPackages(Order orderInfo){                                                          

            dealHotelBusiness( orderInfo ); 

            dealPassengerTicketBusiness( orderInfo );  

            this.sendMesg( orderInfo );

            this.sendEmial( orderInfo );  

    }

    四、解决方案

            要解决上面的问题,必须要实现发送短信方法的增强,使其能够成为事务或者异步方法,即让代理生效。spring的解决方案如下:

            1、在spring配置文件xml新增如下语句:

            先开启cglib代理,开启 exposeProxy=true,暴露代理对象

            <aop:aspectj-autoproxy expose-proxy="true"/>

            2、使用AopContext 获取当前对象的动态代理。

            修改配置文件后,代码修改,用获取到的动态代理去执行发送短信方法,如下:

            TourServer currentProxy = (TourServer )AopContext.currentProxy();

            currentProxy.sendMesg(orderInfo);

            currentProxy.sendEmail(orderInfo);

    相关文章

      网友评论

          本文标题:Spring中解决事务以及异步注解失效

          本文链接:https://www.haomeiwen.com/subject/kyadqqtx.html