一.背景
事务管理对于企业应用而言至关重要。它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性。就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作过程中机器突然出故障的情况,此时,事务就必须确保出故障前对账户的操作不生效,就像用户刚才完全没有使用过取款机一样,以保证用户和银行的利益都不受损失。事务特性原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用;一致性(Consistency):一旦事务完成(不管是成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏;隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏;持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中;事务类型编程式事务:通过编程代码在业务逻辑时需要时自行实现,粒度更小;声明式事务:通过注解或XML配置实现;JDBC事务:即为上面说的数据库事务中的本地事务,通过connection对象控制管理;JTA事务:指Java事务API(JavaTransactionAPI),是JavaEE数据库事务规范,JTA只提供了事务管理接口,由应用程序服务器厂商(如WebSphereApplicationServer)提供实现,JTA事务比JDBC更强大,支持分布式事务;本地事务:普通事务,独立一个数据库,能保证在该数据库上操作的ACID;分布式事务:涉及两个或多个数据库源的事务,即跨越多台同类或异类数据库的事务(由每台数据库的本地事务组成),分布式事务旨在保证这些本地事务的所有操作的ACID,使事务可以跨越多台数据库;数据库分为本地事务和全局事务Java事务类型分为JDBC事务和JTA事务按是否通过编程分为声明式事务和编程式事务Spring事务管理的两种方式优点:缺点:最细粒度只能是作用到方法级别,无法做到像编程事务那样可以作用到代码块级别;实现方式:声明式事务的约定流程:
首先Spring通过事务管理器(PlatformTransactionManager的子类)创建事务,与此同时会把事务定义中的隔离级别、超时时间等属性根据配置内容往事务上设置。而根据传播行为配置采取一种特定的策略,后面会谈到传播行为的使用问题,这是Spring根据配置完成的内容,你只需要配置,无须编码。然后,启动开发者提供的业务代码,我们知道Spring会通过反射的方式调度开发者的业务代码,但是反射的结果可能是正常返回或者产生异常返回,那么它给的约定是只要发生异常,并且符合事务定义类回滚条件的,Spring就会将数据库事务回滚,否则将数据库事务提交,这也是Spring自己完成的。
编程式事务每次实现都要单独实现,但业务量大且功能复杂时,使用编程性事务无疑是痛苦的;而声明式事务不同,声明式事务属于非侵入性,不会影响业务逻辑的实现,只需在配置文件中做相关的事务规则声明(或通过基于
Transactional注解的方式),便可以将事务规则应用到业务逻辑中;非侵入式的开发方式,声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持;是侵入性事务管理,直接使用底层的PlatformTransactionManager、使用TransactionTemplate(Spring推荐使用);编程式事务管理对基于POJO的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、 如果用这个注解描述一个方法的话,线程已经跑到方法里面,如果已经过去60秒了还没跑完这个方法并且线程在这个方法中的后面还有涉及到对数据库的增删改查操作时会报事务超时错误(会回滚)。 如果已经过去60秒了还没跑完但是后面已经没有涉及到对数据库的增删改查操作,那么这时不会报事务超时错误(不会回滚)。Spring管理事务默认回滚的异常是什么? 答案是:RuntimeException或者Error。 注意:如果事务在try{}catch(Exceptione){e.printStackTrace();}中跑,并且catch中只是打印e的话,那么事务不会rollback。因为异常被catch掉了,框架不知道发生了异常。 如果想要rollback,可以加上rollbackFor=Exception.class,然后: ①在方法上添加throwsException,将方法中出现的异常抛出给spring事务, ②去掉方法体中的trycatch ③catch(Exceptione){throwe;}继续向上抛,目的是让spring事务捕获这个异常。 rollbackFor=Exception.class,catch(){ thrownewRunTimeException(); } 如果不加rollbackFor=Exception.class,抛出newException()是不会回滚的。Spring源码如下: publicbooleanrollbackOn(Throwableex){ return(exinstanceofRuntimeExceptionexinstanceofError); } 如果是RuntimeException或Error的话,就返回True,表示要回滚,否则返回False,表示不回滚。 只有spring事务捕获到Exception异常后,
Transactional(rollbackFor=Exception.class),才会起到应有的作用;catch(Exceptione){e.printStackTrace();}这句是捕获try中出现的Exception然后将异常信息打印出来,仅仅是打印出来,然后什么也没干。 Transactional(timeout=60,rollbackFor=Exception.class)与rollbackFor=Exception.class的作用是 1.让checked例外也回滚:在整个方法前加上Transactional(rollbackFor=Exception.class) 2.让unchecked例外不回滚:Transactional(notRollbackFor=RunTimeException.class) checkedUncheckedexception是运行时错误。使用Transactional注解