在Controller中添加事务管理

文章参考了此博客: https://blog.csdn.net/qq_40594137/article/details/82772545

写这篇文章之前先说明一下:

       1. Controller中添加事务管理,是可行的,但是强烈不推荐,因为不符合实际开发场景,还会导致一系列问题

       2. 事务请在Service处理,所有的业务逻辑请写在 Service, Service中异常请抛出,慎用 try...catch捕获异常

写这边文章的背景:

       公司有个老的项目,springMVC + spring + mybatis,事务是在Service层处理的,但是之前的开发人员把很多业务逻辑写在了 Controller,出现了操作失败仍然将数据写入数据库的bug.....,于是开始研究在 Controller中添加事务管理

Controller中添加事务管理步骤:

    1. spring.xml中事务配置不变

扫描二维码关注公众号,回复: 8232067 查看本文章

    2. 在spring-mvc.xml中定义事务配置:

         A: 命名空间中 加入约束 不加项目启动会报异常:
             xmlns:tx="http://www.springframework.org/schema/tx"
             http://www.springframework.org/schema/tx      http://www.springframework.org/schema/tx/spring-tx-4.0.xsd

         B:  定义事务注解解析  <tx:annotation-driven transaction-manager="transactionManager" /> 

   3. 在需要控制事务的Controller 类或者方法上使用 @Transactional(rollbackFor = {Exception.class}) ,当出现异常回滚

       需要注意的是:  Controller层只支持 @Transactional 注解式事务!

                           

关于为什么要在spring-mvc.xml中添加 <tx:annotation-driven transaction-manager="transactionManager" />  的说明:

     错误的方式----通过修改spring.xml中的配置来实现在controller中控制事务会发现事务无效,如下:

<aop:config>  
    <aop:advisor advice-ref="txAdvice" pointcut="execution(* net.*.controller.*.*(..))"/></aop:config> 

      原因如下:  spring容器和spring-mvc是父子容器。在服务器启动时,会先加载web.xml配置文件 ==> 再加载spring配置文件 ==> 再回到web.xml【加载监听器;加载过滤器;加载前端控制器】==>再加载springMVC配置文件,在Spring配置文件中,我们扫描注册的是service实现类,就算扫描注册了controller 也会在后面加载SpringMVC配置文件[扫描注册controller]覆盖掉,所以想要在controller中实现事务管理,仅在spring配置文件配置<tx:annotation-driven>或<aop:config>是没有效果的,必须将事务配置定义在Spring MVC的应用上下文(spring-mvc.xml)中。在spring-framework-reference.pdf文档中说明了: <tx:annoation-driven/>只会查找和它在相同的应用上下文件中定义的bean上面的@Transactional注解

关于 @Transactional 注解的一些说明:

     有篇博客写的很好,我就直接链接了  https://www.jianshu.com/p/befc2d73e487

关于@Transaction 事务不起作用的总结:

       @Transaction不起作用的情况:1.静态(static )方法 

                                                         2.(private)私有化方法  

                                                         3.当本类的使用@Transactional的方法被本类的其它没有开启事务的方法调用时,不会开启事务。

                                                             使用@Transactional的方法被其它类调用时,按照正常的事务传播行为规则开启事务

                                                         4.未开启注解解析: 配置文件必须加<tx:annotation-driven />,否则不解析@Transactional

                                                         5.异常被try{}catch(){}捕捉到了,有异常就不会回滚。

                                                         6. 数据库引擎要支持事务: 如果是mysql,注意表要使用支持事务的引擎,比如innodb,如果是myisam,事务是不起作用的

项目中问题的最终处理:

              由于 Controller 层中异常不能直接抛到用户,对异常进行了try{}catch(){},导致事务回滚失效,无法通过在 Controller 层添加事务管理来实现事务功能,

       所以只能有用以下方式来处理:

       1. 将业务逻辑代码移到 service 来处理 : 推荐方法

       2. 如果业务逻辑复杂,在维护的时候无法保证逻辑正确的情况下,只有手动编写事务代码来实现回滚了,具体代码如下:(不推荐)

         

//在每个controller中注入transactionManager
@Resource
private PlatformTransactionManager transactionManager;
 
@PostMapping(value = "setCode")
@ResponseBody
public void setCode(Invoice invoice, InvoiceAddress invoiceAddress,String token,String orderIDs,
                    Integer pid,HttpServletResponse response){
 
    DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
    defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition);
 
    try {
        invoiceService.insert(token,pid,invoice);
        int iID= invoice.getId();
        String substring = orderIDs.substring(0, orderIDs.length()-1);
        String[] split = substring.split(",");
        for (String string2 : split) {
            bOrderService.updateIStatus("1",string2);
        }
        invoiceOrderService.insert(iID,substring);
        if(Integer.parseInt(invoice.getiType())==1){
            invoiceAddressService.insert(iID,invoiceAddress);
        }
 
        System.out.println("======制造一个运行时异常aa======");
        System.out.println("运行时异常:"+100/0);
 
        //没有异常便手动提交事务
        transactionManager.commit(status);
        printJson(response,result(200,"ok"));
    }catch (Exception e){
        //有异常便回滚事务
        transactionManager.rollback(status);
        e.printStackTrace();
        printJson(response,result(500,"false"));
    }
 
}

  

 

  

      

      

猜你喜欢

转载自www.cnblogs.com/huaixiaonian/p/12061054.html