Spring事务的管理类型分为两种:编程式事务和声明式事务。编程式事务管理,即通过编写代码实现事务管理,包括定义事务的开始,程序正常执行后的事务提交,异常时进行的事务回滚。声明式事务管理,底层是建立在 AOP 的基础之上。其本质是对方法前后进行拦截,在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
Java EE应用的传统事务有两种策略:全局事务和局部事务。全局事务由应用服务器管理,需要底层服务器的JTA支持。局部事务和底层所采用的持久化技术有关,当采用JDBC持久化技术时,需要使用Connection对象来操作事务。
全局事务可以跨多个事务性资源(比如说多个数据库和消息队列);使用局部事务,应用服务器不需要参与事务管理,因此不能保证多个事务性资源的事务正确性。
Spring的事务抽象包括三个主要的接口,即PlatformTransactionManager、TransactionDefinition和TransactionStatus,他们之间的关系如下图:
PlatformTransactionManager负责界定事务边界,是Spring事务的核心组件。TransactionDefinition负责定义事务的相关属性,包括隔离级别、传播行为、超时时间和是否为只读事务。PlatformTransactionManager根据TransactionDefinition的属性定义来开启相关事务。事务开启之后到事务结束期间的事务状态由TransactionStatus负责。
PlatformTransactionManager有三个方法,其源码为:
public interface PlatformTransactionManager{
//获得事务的方法
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
//事务提交方法
void commit(TransactionStatus status) throws TransactionException;
//事务回滚方法
void rollback(TransactionStatus status) throws TransactionException;
}
事务的属性:
事务的属性主要定义在TransactionDefinition中,包括:
- 事务的隔离级别
- 事务的传播行为
- 事务的超时时间
- 是否为只读事务
事务的隔离级别:
TransactionDefinition内定义了五个常量用于标志可供选择的隔离级别:
- ISOLATION_DEFAULT:表示使用数据库默认的隔离级别,通常情况下是READ COMMITTED(提交读/不可重复读),但是MySQL的是REPEATABLE READ(可重复读)。
- ISOLATION_READ_UNCOMMITTED:对应READ UNCOMMITTED(未提交读)隔离级别,会有脏读、不可重复读和幻读问题。
- ISOLATION_READ_COMMITTED:对应READ COMMITTED(提交读)隔离级别,会有不可重复读和幻读问题。
- ISOLATION_REPEATABLE_READ:对应REPEATABLE READ(可重复读)隔离级别,会有幻读问题。
- ISOLATION_SERIALIZABLE:对应SERIALIZABLE(可串行化)隔离级别,可以避免脏读、幻读和不可重复读,但是并行效率最低。
Spring支持4个标准的隔离级别,但最终事务是否以指定的隔离级别执行,则由底层数据资源决定。如果Spring指定的隔离级别当前数据库不支持,则以数据库默认的隔离级别执行。
事务的传播行为:
Spring事务的传播行为表示整个事务处理过程所跨越的业务对象,将以什么样的行为参与事务。比如,当有FoobarService调用FooService和BarService两个方法的时候,FooService的业务方法和BarService的业务方法可以指定它们各自的传播行为。
TransactionDefinition提供了以下七种可供选择的事务传播行为:
- PROPAGATION_REQUIRED:如果当前存在一个事务,则加入当前事务。如果当前不存在事务,则创建一个新事务。总之,要至少保证在一个事务中运行。通常作为默认的事务传播行为。
- PROPAGATION_SUPPORTS:如果当前存在事务,则加入当前事务。如果当前不存在事务,则直接执行。
- PROPAGATION_MANDATORY:强制要求当前存在一个事务,如果当前不存在事务,则直接抛出异常。如果某个方法需要事务支持,但自身又不管理事务提交或回滚,那么比较适用该传播行为。
- PROPAGATION_REQUIRED_NEW:不管当前是否存在事务,都会创建新的事务。如果当前存在事务,则将当前事务挂起。如果某个业务对象所做的事情不想影响到外层事务,则适合该传播行为。
- PROPAGATION_NOT_SUPPORT:不支持当前事务,要求在没有事务的情况下执行。如果当前存在事务,当前事务原则上将被挂起,但这要看对应的PlatformTransactionManager实现类是否支持事务的挂起。
- PROPAGATION_NEVER:永远不需要当前存在事务,如果当前存在事务,则直接抛出异常。
- PROPAGATION_NESTED:如果当前存在事务,则在当前事务中创建一个嵌套事务。如果当前不存在事务,则创建一个新事务,在新事务中执行。注意与PROPAGATION_REQUIRED_NEW区别,在当前存在事务的情况下,PROPAGATION_NESTED创建的是内嵌事务,是寄生于外层事务的,内部事务的内容也是属于外部事务的内容,其不能独立于外部事务存在,它的地位低于外层事务,并且不会挂起外层事务,内嵌事务运行的时候,外层事务的状态也是active状态。而PROPAGATION_REQUIRED_NEW创建的事务与外部事务是同级的,二者独立存在而互不干扰,并且PROPAGATION_REQUIRED_NEW创建新事务后会将当前事务挂起。该传播行为是Spring独有的。其需要特定的PlatformTransactionManager实现类支持。
TransactionStatus代表事务本身,它提供了简单的控制事务执行和查询事务状态的方法,其源码:
public interface TransactionStatus{
//判断事务是否为新建的事务
boolean isNewTransaction();
//设置事务回滚
void setRollbackOnly();
//查询事务是否已有回滚标志
boolean isRollbackOnly();
}