Spring中事务处理机制—RuntimeException()和Exception()
1. Java异常体系
Java异常体系结构图:
1.1 Error和Exception
在 Java 中,所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。 Throwable 类 有两个重要的子类 Exception (异常)和 Error (错误)。 Exception 能被程序本身处理( try- catch ), Error 是无法处理的(只能尽量避免)。
-
Exception:程序本身可以处理的异常,可以通过 catch 来进行捕获。 Exception 又可以分为 受检查异常(必须处理) 和 不受检查异常(可以不处理)。
- 受检查异常
Java 代码在编译过程中,如果受检查异常没有被 catch / throw 处理的话,就没办法通过编译 。
除了 RuntimeException及其子类以外,其他的 Exception 类及其子类都属于检查异常 。受检查异常有: IO 相关的异常、 ClassNotFoundException 、 SQLException等。
- 不受检查异常
Java 代码在编译过程中 ,我们即使不处理不受检查异常也可以正常通过编译。
RuntimeException 及其子类都统称为非受检查异常,例如: NullPointExecrption 、 NumberFormatException (字符串转换为数字)、 ArrayIndexOutOfBoundsException (数组越界)、 ClassCastException (类型转换错误)、 ArithmeticException (算术错误)等。
-
Error:程序无法处理的错误,不可以通过catch进行捕获。这些错误发生时,Java 虚拟机(JVM)一般会选择线程终止。
1.2 运行时异常与非运行时异常
- 运行时异常(不检查异常)都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
- 非运行时异常(受检查异常)是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
2. 异常处理总结
Java异常处理方法有:抛出异常,捕捉异常。主要依赖于try、catch、finally、throw、throws五个关键字。
- try—catch。 try:它里面放置可能引发异常的代码,如果代码运行出现了错误,那么执行catch中的代码块
- throws:向外抛出异常,让之后一个接受到该异常的方法区处理
- finally:无论try指定的程序块是否抛出异常,finally中的代码一定会得到执行。
- throw:用于抛出一个实际的异常,抛出的时候是一个异常类的实例化对象,在异常处理中,try语句要捕获的是一个异常对象,那么此异常对象也可以自己抛出。
package methoud;
public class Demo01{
public static void main(String args[]){
try{
throw new Exception("throw手动抛出一个异常") ; // 抛出异常的实例化对象
}catch(Exception e){
System.out.println(e) ;
}
}
};
- 用在方法签名中,用于声明该方法可能抛出的异常,表示此方法不处理异常,而交给方法调用处进行处理。
public class Demo02 {
public static void main(String args[]) throws Exception{
Math m = new Math() ; // 实例化Math类对象
System.out.println("除法操作:" + m.div(10,0)) ;
}
}
class Math{
public int div(int i,int j) throws Exception{ // 定义除法操作,如果有异常,则交给被调用处处理
int temp = i / j ;
return temp ;
}
};
3. Spring事务处理
**Spring事务默认只在发生未被捕获的RuntimeException()时才进行回滚。**但不是RuntimeException或其子类的异常不能够捕获,只是默认情况下不进行回滚。
通过配置来捕获特定的异常并回滚 :
方式1:
在service层不使用try…catch或者在catch中最后加上throw new RuntimeException(),这样程序异常时aop才可以捕获异常并进行回滚。
最终在service上层(如controller层、action层、view层)要继续捕获这个异常并处理。
方式2:
在service层方法上进行配置,改变默认规则,方法如下 :
-
受检查异常也回滚:在整个方法前加上
@Transactional(rollbackFor=Exception.class)
-
不受检查异常不回滚:
@Transactional(notRollbackFor=RunTimeException.class)
-
不需要事务管理的(只查询的)方法:
@Transactional(propagation=Propagation.*NOT_SUPPORTED*)
在整个方法运行前就不会开启事务还可以加上: @Transactional(propagation=Propagation.NOT_SUPPORTED, readOnly=true)
,这样就做成一个只读事务,并可以提高效率。