Spring的事务框架设计理念的基本原则是:让事务管理的关注点和数据访问关注点分离。
Spring的事务抽象包括如下3个主要接口:
PlatformTransactionManager
TransactionDefinition
TransactionStatus
1、TransactionDefinition
TransactionDefinition
主要定义了事务的属性,包括
- 事务的隔离(Isolation)级别
- 事务的传播行为(Propagation Behavior)
- 事务的超时时间(Timeout)
- 是否为只读(ReadOnly)事务
TransactionDefinition
内定义了5个常量用于标识可以提供的隔离级别
ISOLATION_DEFAULT
: 表示数据库的默认隔离级别,通常情况下是Read CommittedISOLATION_READ_UNCOMMITTED
: 对应Read Uncommittd隔离级别,无法避免脏读,不可重复读和幻读ISOLATION_READ_COMMITTED
: 对应Read Committed隔离级别,避免脏读,但是无法避免不可重复读和幻读ISOLATION_REPEATABLE_READ
: 对应Repeatable Read隔离级别,可以避免脏读和不可重复读,但是不能避免幻读。ISOLATION_SERIALIZABLE
: 对应Seriablizable隔离级别,可以避免所有的脏读,不可重复读和幻读,但是并发效率较低
事务的传播行为表示整个事务处理过程所跨越的业务对象,将以什么样的行为参与事务(我们将在声明式事务中更多地依赖该属性),比如,当有FoobarService调用FooService和BarService两个方法的时候,FooService的业务方法和BarService的业务方法可以指定各自的事务传播行为。
FooService的业务方法的传播行为被我们指定为Required,表示如果当前存在事务的话,则加入当前事务,因为FoobarService在调用FooService的业务方法的时候已经启动了一个事务,所以,FooService的业务方法会直接加入FoobarService启动的事务中,BarService的业务方法的传播行为被指定为RequiredNew,表示无论当前是否存在事务,都需要重新启动一个新的事务,所以,它使用的是自己启动的事务。
针对事务的传播行为,TransactionDefinition
提供了以下几种选择:
PROPAGATION_REQUIRED
:如果当前存在事务,则加入当前事务。如果不存在任何事务,则创建一个新的事务,总之,要至少保证在一个事务中运行。PROPAGATION_REQUIRED
通常作为默认的事务传播行为PROPAGATION_SUPPORTS
:如果当前存在一个事务,则加入当前事务。如果当前不存在事务,则直接执行。对于一些查询方法来说,PROPAGATION_SUPPORTS
通常是比较合适的传播行为选择。如果当前方法直接执行,那么不需要事务的支持。如果当前方法被其他方法调用,而其他方法启动了一个事务,可以保证PROPAGATION_SUPPORTS
当前方法能够加入当前事务,并洞察当前事务对数据资源所做的更新。例如: A.service()会首先更新数据库,然后调用B.service()进行查询,那么,如果B.service()是PROPAGATION_SUPPORTS
的传播行为,就可以读取A.service()之前所做的更新结果。PROPAGATION_MANDATORY
:PROPAGATION_MANDATORY
强制要求当前存在一个事务,如果不存在,则抛出异常。如果某个方法需要事务支持,但自身又不管理事务提交和回滚,那么比较适合使用PROPAGATION_MANDATORY
PROPAGATION_REQUIRES_NEW
: 不管当前是否存在事务,都会创建新的事务,如果当前存在事务,则会将当前事务挂起(Suspend)。如果某个业务对象所做的事情不想影响到外层的事务,PROPAGATION_REQUIRES_NEW
应该是最佳的选择。比如,假设当前的业务方法需要向数据库更新某些日志信息,即时日志信息更新失败,我们也不想因为该业务方法的事务回滚,而影响到外层事务的成功提交。因为这种情况下,当前业务方法的事务成功与否对外城事务来说是无关紧要的。PROPAGATION_NOT_SUPPORTED
: 不支持当前事务,而是在没有事务的情况下执行。如果当前存在事务,则挂起事务(Suspend),但是这要看PlatformTransactionManager实现类是否支持事务的挂起。PROPAGATION_NEVER
: 永远不需要当前存在事务,如果存在事务,则抛出异常。PROPAGATION_NESTED
: 如果存在事务,则在当前事务的一个嵌套事务中执行,否则与PROPAGATION_REQUIRED
类似,创建新的事务。
TransactionDefinition
只是一个接口定义,要为PlatformTransactionManager
创建事务提供信息,需要由相应的实现类提供支持。
我们将TransactionDefinition
的相关实现类按照编程式事务场景和声明式事务长青划分为两个分支。DefaultTransactionDefinition
是TransactionDefinition
接口的默认实现类,他提供了各种事务属性的默认值,并且通过他的setter方法,可以更改这些默认设置。这些默认值包括
propagationBehavior = PROPAGATION_REQUIRED
isolationLevel = ISOLATION_DEFAULT
timeout = TIMEOUT_DEFAULT
readOnly = false
TransactionTemplate
是Spring提供的进行编程式事务管理的模板方法类,他直接继承自DefaultTransactionDefinition
,所以我们使用TransactionTemplate
的时候就可以直接通过TransactionTemplate
本身提供事务控制属性。
TransactionAttribute
是继承自TransactionDefinition
的接口定义,主要面向Spring AOP进行声明式事务管理的场合。他在TransactionDefinition
定义的基础上添加了一个rollbackOn
方法。可以通过声明的方式指定业务方法在抛出那些异常的情况下回滚事务。TransactionAttribute
的默认实现类时DefaultTransactionAttribute
,同时继承DefaultTransactionDefinition
。
2、TransactionStatus介绍
TransactionStatus
接口定义表示整个事务处理过程中的事务状态。在事务处理过程中,我们可以使用TransactionStatus
进行如下工作。
- 使用
TransactionStatus
提供的相应方法查询事务状态。 - 使用
setRollbackOnly()
方法标记当前事务以使其回滚。 - 如果相应的
PlatformTransactionManager
支持Savepoint,可以通过TransactionStatus
在当前事务中创建内部嵌套事务。
3、PlatformTransactionManager介绍
org.springframework.transaction.PlatformTransactionManager
是Spring事务抽象架构的核心接口,他的主要作用是为应用程序提供事务界定的统一方式。接口定义如下:
1 | public interface PlatformTransactionManager { |
Spring的事务框架针对不同的数据访问方式以及全局事务场景,提供了相应的PlatformTransactionManager
的实现类,例如针对JDBC/iBatis的DataSourceTransactionManager
。
对于层次划分清晰的应用来说,我们通常都是将事务管理放在Service层,而将数据访问层放在DAO层,这样做的目的是可以不用因为事务管理代码放在DAO层而降低数据访问逻辑的重用性。也可以在service层根据应用逻辑,来决定提交或者回滚事务,一般的service对象可能需要在同一个业务方法中调用多个数据访问的方法。
事务管理的实施通常有两种方式,即编程式事务管理和声明方式事务管理。对于这两种事务管理方式,Spring事务框架可以说是青出于蓝而胜于蓝。
一、编程式事务管理
通过Spring进行编程式事务管理有两种方式,要么直接使用PlatformTransactionManager
,要么使用更方便的TransactionTemplate
,二者各有优点,但是总体上来说,推荐使用TransactionTemplate
进行编程时事务管理。
1、直接使用PlatformTransactionManager
进行编程式事务管理
PlatformTransactionManager
接口定义了事务界定的基本操作,我们可以直接使用PlatformTransactionManager
进行编程式事务管理。一般不会自己实现PlatformTransactionManager
接口,可以使用Spring
为我们提供的实现类,用DataSourceTransactionManager
实现类代码如下:
1 |
|
2、使用TransactionTemplate进行编程式事务管理
TransactionTemplate
对与PlatformTransactionManager
相关事务界定操作以及相关的异常处理进行了模块化封装,开发人员更多地关注于通过响应的Callback接口提供具体的事务界定内容即可。Spring针对TransactionTemplate
提供了两个Callback接口,TransactionCallback
和TransactionCallbackWithoutResult
,二者的区别是是否需要返回执行结果。