zoukankan      html  css  js  c++  java
  • spring中的事务回滚

    1.定义

    事务的提交是指事务里的所有操作都正常完成。

    事务的回滚是指程序或数据处理错误,将程序或数据恢复到上一次正确状态的行为。

    2.代码中事务控制的3种方式

      • 编程式事务:就是直接在代码里手动开启事务,手动提交,手动回滚。对于编程式事务管理,spring推荐使用TransactionTemplate。

      • 声明式事务:就是使用SpringAop配置事务,这种方式大大的简化了编码,需要注意的是配置切入点表达式一定要写正确。声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。

      • 注解事务:直接在Service层的方法上面加上@Transactional注解,个人比较喜欢用这种方式。

    3.编程式事务和声明式事务对比

    显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

    4.事务不回滚的原因

        在工作中,看过别人写的代码出现了事务不回滚的现象。当然,事务不回滚的都是采用的声明式事务或者是注解事务;编程式事务都是自己写代码手动回滚的,因此是不会出现不回滚的现象。

        再说下声明式事务和注解事务回滚的原理:当被切面切中或者是加了注解的方法中抛出了RuntimeException异常时,Spring会进行事务回滚。默认情况下是捕获到方法的RuntimeException异常,也就是说抛出只要属于运行时的异常(即RuntimeException及其子类)都能回滚;但当抛出一个不属于运行时异常时,事务是不会回滚的。

        下面说说我经常见到的3种事务不回滚的产生原因:

      • (1)声明式事务配置切入点表达式写错了,没切中Service中的方法

      • (2)Service方法中,把异常给try catch了,但catch里面只是打印了异常信息,没有手动抛出RuntimeException异常

      • (3)Service方法中,抛出的异常不属于运行时异常(如IO异常),因为Spring默认情况下是捕获到运行时异常就回滚

    5.如何保证事务回滚

        正常情况下,按照正确的编码是不会出现事务回滚失败的。下面说几点保证事务能回滚的方法

      • (1)如果采用声明式事务,一定要确保切入点表达式书写正确

      • (2)如果Service层会抛出不属于运行时异常也要能回滚,那么可以将Spring默认的回滚时的异常修改为Exception,这样就可以保证碰到什么异常都可以回滚。具体的设置方式也说下:

                            ① 声明式事务,在配置里面添加一个rollback-for,代码如下

     <tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>

                           ② 注解事务,直接在注解上面指定,代码如下

    @Transactional(rollbackFor=Exception.class)
    • (3)只有非只读事务才能回滚的,只读事务是不会回滚的

    • (4)如果在Service层用了try catch,在catch里面再抛出一个 RuntimeException异常,这样出了异常才会回滚

    • (5)如果你不喜欢(4)的方式,你还可以直接在catch后面写一句回滚代码(TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();来实现回滚,这样的话,就可以在抛异常后也能return 返回值;比较适合需要拿到Service层的返回值的场景。具体的用法可以参见考下面的伪代码                            

      /** TransactionAspectSupport手动回滚事务:*/
             @Transactional(rollbackFor = { Exception.class })  
             public boolean test() {  
                  try {  
                     doDbSomeThing();    
                  } catch (Exception e) {  
                       e.printStackTrace();     
                       //就是这一句了, 加上之后抛了异常就能回滚(有这句代码就不需要再手动抛出运行时异常了)                
      TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      return false;
  • 相关阅读:
    数据结构基础(21) --DFS与BFS
    数据结构基础(20) --图的存储结构
    数据结构基础(19) --堆与堆排序
    数据结构基础(18) --哈希表的设计与实现
    数据结构基础(17) --二叉查找树的设计与实现
    数据结构基础(16) --树与二叉树
    数据结构基础(15) --基数排序
    数据结构基础(14) --链式队列的设计与实现
    在centOS6.5 上安装使用pipework
    数据结构基础(13) --链式栈的设计与实现
  • 原文地址:https://www.cnblogs.com/BruceV/p/12027797.html
Copyright © 2011-2022 走看看