e2

滴滴侠,fai抖

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

一、结论 

Spring的事务管理默认只对出现运行期异常(java.lang.RuntimeException及其子类)进行回滚。 

如果一个方法抛出Exception或者Checked异常,Spring事务管理默认不进行回滚。 

关于异常的分类一下详细介绍: 

1、基本概念 

看java的异常结构图

 

Throwable是所有异常的根,java.lang.Throwable 

Error是错误,java.lang.Error 

Exception是异常,java.lang.Exception 

2、Exception 

一般分为Checked异常和Runtime异常,所有RuntimeException类及其子类的实例被称为Runtime异常,不属于该范畴的异常则被称为CheckedException。 

①Checked异常 

只有java语言提供了Checked异常,Java认为Checked异常都是可以被处理的异常,所以Java程序必须显示处理Checked异常。如果程序没有处理Checked异常,该程序在编译时就会发生错误无法编译。这体现了Java的设计哲学:没有完善错误处理的代码根本没有机会被执行。对Checked异常处理方法有两种 

(1) 当前方法知道如何处理该异常,则用try...catch块来处理该异常。 

(2) 当前方法不知道如何处理,则在定义该方法是声明抛出该异常。

Java代码  收藏代码
  1. package cn.xy.test;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. /** 
  6.  * Checked异常测试方法 
  7.  *  
  8.  * @author xy 
  9.  */  
  10. public class CheckedExceptionMethods {  
  11.   
  12.     // 总异常类,既有checkedException又有RuntimeException,所以其中的checkedException必须处理  
  13.     public void method1() throws Exception {  
  14.         System.out.println("我是抛出异常总类的方法");  
  15.     }  
  16.   
  17.     // 捕获并处理这个异常  
  18.     public void testMethod1_01() {  
  19.         try {  
  20.             method1();  
  21.         } catch (Exception e) {  
  22.             e.printStackTrace();  
  23.         }  
  24.     }  
  25.   
  26.     // 把异常传递下去  
  27.     public void testMethod1_02() throws Exception {  
  28.         method1();  
  29.     }  
  30.   
  31.     public void testMethod1_03() throws Exception {  
  32.         throw new Exception();  
  33.     }  
  34.   
  35.     public void testMethod1_04() {  
  36.         try {  
  37.             throw new Exception();  
  38.         } catch (Exception e) {  
  39.             e.printStackTrace();  
  40.         }  
  41.     }  
  42.   
  43.     // checkedException典型代表IOException  
  44.     public void method2() throws IOException {  
  45.         System.out.println("我是抛出IO异常的方法");  
  46.     }  
  47.   
  48.     public void testMethod2_01() {  
  49.         try {  
  50.             method2();  
  51.         } catch (Exception e) {  
  52.             e.printStackTrace();  
  53.         }  
  54.     }  
  55.   
  56.     public void testMethod2_02() throws Exception {  
  57.         method2();  
  58.     }  
  59. }   

我们比较熟悉的Checked异常有 

Java.lang.ClassNotFoundException 

Java.lang.NoSuchMetodException 

java.io.IOException

②RuntimeException 

Runtime如除数是0和数组下标越界等,其产生频繁,处理麻烦,若显示申明或者捕获将会对程序的可读性和运行效率影响很大。所以由系统自动检测并将它们交给缺省的异常处理程序。当然如果你有处理要求也可以显示捕获它们。 

Java代码  收藏代码
  1. package cn.xy.test;  
  2.   
  3. /** 
  4.  * 运行时异常测试方法 
  5.  *  
  6.  * @author xy 
  7.  */  
  8. public class RuntimeExcetionMethods {  
  9.   
  10.     public void method3() throws RuntimeException {  
  11.         System.out.println("我是抛出运行时异常的方法");  
  12.     }  
  13.   
  14.     public void testMethod3_01() {  
  15.         method3();  
  16.     }  
  17.   
  18.     public void testMethod1_02() {  
  19.         throw new RuntimeException();  
  20.     }  
  21. }  

 我们比较熟悉的RumtimeException类的子类有 

 Java.lang.ArithmeticException 

 Java.lang.ArrayStoreExcetpion 

 Java.lang.ClassCastException 

 Java.lang.IndexOutOfBoundsException 

 Java.lang.NullPointerException 

3、Error 

当程序发生不可控的错误时,通常做法是通知用户并中止程序的执行。与异常不同的是Error及其子类的对象不应被抛出。 

Error是throwable的子类,代表编译时间和系统错误,用于指示合理的应用程序不应该试图捕获的严重问题。 

Error由Java虚拟机生成并抛出,包括动态链接失败,虚拟机错误等。程序对其不做处理。

二、改变默认方式 

(1)、在@Transaction注解中定义noRollbackFor和RollbackFor指定某种异常是否回滚。 

@Transaction(noRollbackFor=RuntimeException.class) 

@Transaction(RollbackFor=Exception.class) 

这样就改变了默认的事务处理方式。

如果配置了rollbackFor 和 noRollbackFor 且两个都是用同样的异常,那么遇到该异常,还是回滚;
rollbackFor 和noRollbackFor 配置也许不会含盖所有异常,对于遗漏的按照Check Exception 不回滚,unCheck Exception回滚

(2)、在txAdive中增加rollback-for,里面写自己的exception,例如自己写的exception:

<tx:advice id="txAdvice" transaction-manager="transactionManager">

   <tx:attributes>

     <tx:method name="*" rollback-for="com.cn.untils.exception.XyzException"/>

   </tx:attributes>

 </tx:advice>

 

或者

定义不会滚的异常

<tx:advice id="txAdvice">

    <tx:attributes>

       <tx:method name="update*" no-rollback-for="IOException"/>

       <tx:method name="*"/>

    </tx:attributes>

 </tx:advice> 

(3)、spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行commit or rollback(Spring默认取决于是否抛出runtime异常).

 如果抛出runtime exception 并在你的业务方法中没有catch到的话,事务会回滚。 

 一般不需要在业务方法中catch异常,如果非要catch,在做完你想做的工作后(比如关闭文件等)一定要抛出runtime exception,否则spring会将你的操作commit,这样就会产生脏数据.所以你的catch代码是画蛇添足。

如:

try {  

    //bisiness logic code  

} catch(Exception e) {  

    //handle the exception  

}  

由此可以推知,在spring中如果某个业务方法被一个 整个包裹起来,则这个业务方法也就等于脱离了spring事务的管理,因为没有任何异常会从业务方法中抛出!全被捕获并吞掉,导致spring异常抛出触发事务回滚策略失效。

不过,如果在catch代码块中采用页面硬编码的方式使用spring api对事务做显式的回滚,这样写也未尝不可

 

三、启示 

这就要求我们在自定义异常的时候,让自定义的异常继承自RuntimeException,这样抛出的时候才会被Spring默认的事务处理准确处理。

posted on 2017-03-07 16:31  纯黑Se丶  阅读(498)  评论(0编辑  收藏  举报