上文说完了事务嵌套,那这里也不得不说下事务回滚是怎么回事。
spring声明式事务管理默认对非检查型异常和运行时异常进行事务回滚,而对检查型异常则不进行回滚操作。
1:首先说明一下异常是什么,有什么区分,以及常见的异常?
Java里面异常分为两大类:checkedexception(检查异常)和unchecked exception(未检查异常-也叫运行时异常RuntimeException)
对于未检查异常也叫RuntimeException(运行时异常),对于运行时异常,java编译器不要求你一定要把它捕获或者一定要继续抛出,但是对checkedexception(检查异常)要求你必须要在方法里面或者捕获或者继续抛出。
Thorwable是所有异常和错误的超类,
有两个子类Error和Exception,分别表示错误和异常。
其中异常类Exception又分为运行时异常(RuntimeException)和非运行时异常。
这两种异常有很大的区别,也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。
下面将详细讲述这些异常之间的区别与联系:
1、Error与Exception
Error是程序无法处理的错误,比如OutOfMemoryError、ThreadDeath等。
这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常。
程序中应当尽可能去处理这些异常。
2、运行时异常和非运行时异常
2.1:运行时异常都是RuntimeException类及其子类异常,
如NullPointerException、IndexOutOfBoundsException等,
这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。
这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
2.2:非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。
从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。
IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
例如:常见的运行时异常,RuntimeException异常:
NullPointerException
ClassCastException
ArrayIndexOutOfBoundsException
StringIndexOutOfBoundsException
NumberFormatException
ArithmeticException 零做除数
这些也基本上就是平常代码运行阶段经常遇到的那些异常,其实都是RuntimeException的子类。
你如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。
检查异常 Checked ,一般在编译器就被检出,
ClassNotFoundException
NosuchFieldException
NosuchMethodException
2:spring事务回滚
spring声明式事务管理默认对非检查型异常和运行时异常进行事务回滚,而对检查型异常则不进行回滚操作。
1,Spring事务回滚机制是这样的:当所拦截的方法有指定异常抛出,事务才会自动进行回滚!
我们需要注意的地方有四点: 如果你在开发当中引入Spring进行事务管理,但是事务没能正常的自动回滚,可以对照下面四点,缺一不可!
①被拦截方法-—— 注解式:方法或者方法所在类被@Transactional注解;
拦截配置式:<tx:method />应该包含对该方法,名称格式的定义;
且方法需要在expression定义的范围内;
②异常—— 该方法的执行过程必须出现异常,这样事务管理器才能被触发,并对此做出处理;
③指定异常—— 默认配置下,事务只会对Error与RuntimeException及其子类这些UNChecked异常,做出回滚。 一般的Exception这些Checked异常不会发生回滚(如果一般Exception想回滚要做出配置);
④异常抛出—— 即方法中出现的指定异常,只有在被事务管理器捕捉到以后,事务才会据此进行事务回滚;
1,不捕捉,会回滚:没有trycatch
2,如果异常被try{}捕捉到,那么事务管理器就无法再捕捉异常,所以就无法做出反应,事务不回滚;
3,如果异常被try{}捕捉了,我们还可以在Catch(){}中throw new RuntimeException(),手动抛出运行时异常供事务管理器捕捉;
2,在实际开发中,有时并没有异常发生,但是由于事务结果未满足具体业务需求,所以我们不得不手动回滚事务!
有如下两种方法:
①手动抛出异常(如果你没有配置一般异常事务回滚,请抛出运行时异常)
throw new RuntimeException();
②编程式实现手动回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
注意:尽管可以采用编程式方法回滚事务,但“回滚”只是事务的生命周期之一,所以要么编程实现事务的全部必要周期,要么仍要配置事务切点,即,将事务管理的其他周期交由Spring的标识!
3:spring事务的默认配置
Spring的事务管理默认是针对unchecked exception(未检查 RuntimeException)回滚,也就是默认对Error异常和RuntimeException异常以及其子类进行事务回滚,且必须对抛出异常,若使用try-catch对其异常捕获则不会进行回滚!(Error异常和RuntimeException异常抛出时不需要方法调用throws或try-catch语句);
checked异常,checked异常必须由try-catch语句包含或者由方法throws抛出,且事务默认对checked异常不进行回滚。
在service类前加上@Transactional,声明这个service所有方法需要事务管理。每一个业务方法开始时都会打开一个事务。
Spring默认情况下会对运行期例外(RunTimeException)进行事务回滚。这个例外是unchecked
如果遇到checked意外就不回滚。
如何改变默认规则:
1 让checked例外也回滚:在整个方法前加上 @Transactional(rollbackFor=Exception.class)
2 让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
3 不需要事务管理的(只查询的)方法:@Transactional(propagation=Propagation.NOT_SUPPORTED)
注意: 如果异常被try{}catch{}了,事务就不回滚了,如果想让事务回滚必须再往外抛try{}catch{throw Exception}。