spring 事务回滚

一、遇到的问题spring

  当咱们一个方法里面有多个数据库保存操做的时候,中间的数据库操做发生的错误。伪代码以下:数据库

public method() {
    Dao1.save(Person1);
    Dao1.save(Person2);

    Dao1.save(Person2);//假如这句发生了错误,前面的两个对象会被保存到数据库中
    Dao1.save(Person2);
}

  期待的状况:发生错误以前的全部数据库保存操做都回滚,即不保存编程

  正常状况:前面的数据库操做会被执行,而发生数据库操做错误开始及以后的全部的数据保存操做都将失败。这样子应该都不是咱们要的结果吧。架构

  当遇到这种状况,咱们就可使用Spring的事务解决这个问题。ui

二、异常的一些基本知识spa

1) 异常的架构code

  异常的继承结构:Throwable为基类,Error和Exception继承Throwable,RuntimeException和IOException等继承Exception。Error和RuntimeException及其子类成为未检查异常(unchecked),其它异常成为已检查异常(checked)。 orm

2)Error异常对象

  Error表示程序在运行期间出现了十分严重、不可恢复的错误,在这种状况下应用程序只能停止运行,例如JAVA 虚拟机出现错误。Error是一种unchecked Exception,编译器不会检查Error是否被处理,在程序中不用捕获Error类型的异常。通常状况下,在程序中也不该该抛出Error类型的异常。blog

3)RuntimeException异常

  Exception异常包括RuntimeException异常和其余非RuntimeException的异常。
  RuntimeException 是一种Unchecked Exception,即表示编译器不会检查程序是否对RuntimeException做了处理,在程序中没必要捕获RuntimException类型的异常,也没必要在方法体声明抛出 RuntimeException类。RuntimeException发生的时候,表示程序中出现了编程错误,因此应该找出错误修改程序,而不是去捕获RuntimeException。

4)Checked Exception异常

  Checked Exception异常,这也是在编程中使用最多的Exception,全部继承自Exception而且不是RuntimeException的异常都是checked Exception,上图中的IOException和ClassNotFoundException。JAVA 语言规定必须对checked Exception做处理,编译器会对此做检查,要么在方法体中声明抛出checked Exception,要么使用catch语句捕获checked Exception进行处理,否则不能经过编译。

三、实例

  这里使用的事务配置以下:

 <!-- Jpa 事务配置 -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    
    <!-- 开启注解事务 -->
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

  在spring的配置文件中,若是数据源的defaultAutoCommit设置为True了,那么方法中若是本身捕获了异常事务不会回滚的,若是没有本身捕获异常则事务会回滚,以下例
好比配置文件里有这么条记录

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> 

<property name="xxx" value="xxx"/>

<property name="xxx" value="xxx"/>

....
<property name="defaultAutoCommit" value="true" />

</bean>

  可能你会发现你并无配置这个参数,是否是他就不会自动提交呢?答案是否是的,我这里是使用了com.alibaba.druid.pool.DruidDataSource做为数据库链接池,默认的defaultAutoCommit就是true,能够看下面的源码

 

  那么如今有两个状况
  状况1:若是没有在程序中手动捕获异常

@Transactional(rollbackOn = { Exception.class })  
public void test() throws Exception {  
     doDbStuff1();  
     doDbStuff2();//假如这个操做数据库的方法会抛出异常,如今方法doDbStuff1()对数据库的操做   会回滚。  
}  

  状况2:若是在程序中本身捕获了异常

@Transactional(rollbackOn = { Exception.class })  
public void test() {  
     try {  
        doDbStuff1();  
        doDbStuff2();//假如这个操做数据库的方法会抛出异常,如今方法doDbStuff1()对数据库的操做  不会回滚。  
     } catch (Exception e) {  
           e.printStackTrace();     
     }  
}  

  如今若是咱们须要手动捕获异常,而且也但愿抛异常的时候能回滚肿么办呢?
  下面这样写就行了,手动回滚事务:

@Transactional(rollbackOn = { Exception.class })  
public void test() {  
     try {  
        doDbStuff1();  
        doDbStuff2();  
     } catch (Exception e) {  
          e.printStackTrace();     
          TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//就是这一句了,加上以后,若是doDbStuff2()抛了异常,                                                                                       //doDbStuff1()是会回滚的  
     }  
}  

   致谢:感谢您的阅读!转文请加原文连接,谢谢!

相关文章
相关标签/搜索