Java异常总结和Spring事务处理异常机制浅析

异常的概念和Java异常体系结构

异常是程序运行过程当中出现的错误。本文主要讲授的是Java语言的异常处理。Java语言的异常处理框架,是Java语言健壮性的一个重要体现。java

Thorwable类全部异常和错误的超类,有两个子类ErrorException,分别表示错误和异常。
其中异常类Exception又分为运行时异常(RuntimeException)和非运行时异常,这两种异常有很大的区别,也称之为不检查异常(Unchecked Exception)
和检查异常(Checked Exception)。spring

  • 运行时异常 ---> UncheckedException
  • 非运行时异常--->CheckedException

异常架构

Error和 Exception

  • Error是程序没法处理的错误,好比OutOfMemoryErrorThreadDeath等。这些异常发生时,Java虚拟机(JVM)通常会选择线程终止。编程

  • Exception是程序自己能够处理的异常,这种异常分两大类,运行时异常非运行时异常。程序中应当尽量去处理这些异常。架构

二、运行时异常和非运行时异常

运行时异常都是RuntimeException类及其子类异常,如框架

  • NullPointerException、
  • IndexOutOfBoundsException

这些异常是不检查异常(UncheckedException),程序中能够选择捕获处理,也能够不处理。这些异常通常是由程序逻辑错误引发的,程序应该从逻辑角度尽量避免这类异常的发生。编译是能够经过的jvm

非运行时异常是除RuntimeException之外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,若是不处理,程序就不能编译经过。如IOException、SQLException等以及用户自定义的Exception异常,通常状况下不自定义检查异常。性能

异常的捕获和处理

Java异常的捕获和处理是一个不容易把握的事情,若是处理不当,不但会让程序代码的可读性大大下降,并且致使系统性能低下,甚至引起一些难以发现的错误。.net

Java异常处理涉及到五个关键字,分别是:trycatchfinallythrowthrows线程

try、catch、finally三个语句块应注意的问题

trycatchfinally三个语句块均不能单独使用,三者能够组成 try...catch...finallytry...catchtry...finally三种结构,catch语句能够有一个或多个,finally语句最多一个。
try、catch、finally三个代码块中变量的做用域为代码块内部,分别独立而不能相互访问。若是要在三个块中均可以访问,则须要将变量定义到这些块的外面。
多个catch块时候,只会匹配其中一个异常类并执行catch块代码,而不会再执行别的catch块,而且匹配catch语句的顺序是由上到下。

throw、throws关键字

throw关键字是用于方法体内部,用来抛出一个Throwable类型的异常。设计

若是抛出了检查异常,则还应该在方法头部声明方法可能抛出的异常类型。该方法的调用者也必须检查处理抛出的异常。若是全部方法都层层上抛获取的异常,最终JVM会进行处理,处理也很简单,就是打印异常消息和堆栈信息。
若是抛出的是Error或RuntimeException,则该方法的调用者可选择处理该异常。有关异常的转译会在下面说明。

当抛出的是运行时异常,程序能够选择处理和不处理

public static void main(String[] args) {
    try {
        FileReader file = new FileReader("d:/entitycode");
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        throw new RuntimeException();
    }
}

抛出的是非运行时异常时,程序必需要处理,能够继续往外抛,或者捕获

public static void main(String[] args) throws FileNotFoundException {
    try {
        FileReader file = new FileReader("d:/entitycode");
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        throw new FileNotFoundException();
    }
}
throws关键字用于方法体外部的方法声明部分,用来声明方法可能会抛出某些异常。仅当抛出了检查异常,该方法的调用者才必须处理或者从新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出,而不是囫囵吞枣通常在catch块中打印一下堆栈信息作个勉强处理。下面给出一个简单例子,

Throwable类中的经常使用方法

  • getCause():返回抛出异常的缘由。若是 cause 不存在或未知,则返回 null。
  • getMessage():返回异常的消息信息。
  • printStackTrace():对象的堆栈跟踪输出至错误输出流,做为字段 System.err 的值。

异常处理的通常原则

能处理就早处理,抛出不去还不能处理的就想法消化掉或者转换为RuntimeException处理。由于对于一个应用系统来讲,抛出大量异常是有问题的,应该从程序开发角度尽量的控制异常发生的可能。
对于检查异常,若是不能行之有效的处理,还不如转换为RuntimeException抛出。这样也让上层的代码有选择的余地――可处理也可不处理。
对于一个应用系统来讲,应该有本身的一套异常处理框架,这样当异常发生时,也能获得统一的处理风格,将优雅的异常信息反馈给用户。

Java异常总结

Java将异常区分为Error与Exception,Error是程序无力处理的错误,Exception是程序能够处理的错误。异常处理是为了程序的健壮性。
异常能处理就处理,不能处理就抛出,最终没有处理的异常JVM会进行处理。
异常能够传播,也能够相互转译,但应该根据须要选择合理的异常转译的方向。
对于一个应用系统,设计一套良好的异常处理体系很重要。这一点在系统设计的时候就应该考虑到。
Exception通常分为Checked异常Runtime异常,全部RuntimeException类及其子类的实例被称为Runtime异常,不属于该范畴的异常则被称为CheckedException

Spring事务回滚与异常

Spring被事务管理的方法,须要抛出非检查异常,即运行期异常才能进行回滚

对非检查型类异常能够不用捕获,而检查型异常则必须用try语句块进行处理或者把异常交给上级方法处理总之就是必须写代码处理它。因此必须在service捕获异常,而后再次抛出,这样事务方才起效。

在spring的事务管理环境下,使用unckeckedException能够极大地简化异常的处理,只须要在事务层声明可能抛出的异常(这里的异常能够是自定义的unckecked exception体系),在全部的中间层都只是须要简单throws便可,不须要捕捉和处理,直接到最高层,好比UI层再进行异常的捕捉和处理

在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}。

一个统一的异常层次结构对于提供服务抽象是必需的。 最重要的就是org.springframework.dao.DataAccessException以及其子类了。 须要强调的是Spring的异常机制重点在于应用编程模型。与SqlException和其余数据存取API不一样的是: Spring的异常机制是为了让开发者使用最少, 最清晰的代码。DataAccessException和其余底层异常都是非检查性异常(unchecked exception)。 spring的原则之一就是基层异常就应该是非检查性异常. 缘由以下:

  • 基层异常一般来讲是不可恢复的。
  • 检查性异常将会下降异常层次结构的价值.若是底层异常是检查性的, 那么就须要在全部地方添加catch语句进行捕获。
  • try/catch代码块冗长混乱,并且不增长多少价值。使用检查异常理论上很好, 可是实际上好象并不如此。Hibernate3也将从检查性异常转为非检查性异常。

本文参考:

A
B

相关文章
相关标签/搜索