• 在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中事务配置不变

        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"));
        }
     
    }

      

     

      

          

          

  • 相关阅读:
    Sublime Text3 包管理器、插件安装
    Sublime text3 安装
    VS中的波浪线
    VS的启动方式
    VS常用快捷键
    C#基础性问题
    nginx前端项目发布
    vue父子组件实现数据双向绑定
    常用在线echarts图表
    使用echarts地图踩坑记
  • 原文地址:https://www.cnblogs.com/huaixiaonian/p/12061054.html
Copyright © 2020-2023  润新知