一、遇到的问题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()是会回滚的 } }
致谢:感谢您的阅读!转文请加原文连接,谢谢!