PlatformTransactionManager: (平台)事务管理器
TransactionDefinition: 事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)
TransactionStatus: 事务运行状态
所谓事务管理,其实就是“按照给定的事务规则来执行提交或者回滚操作”。
Spring并不直接管理事务,而是提供了多种事务管理器。Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。
public interface PlatformTransactionManager(){
// 根据指定的传播行为,返回当前活动的事务或创建一个新事务
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
// 使用事务目前的状态提交事务
Void commit(TransactionStatus status) throws TransactionException;
// 对执行的事务进行回滚
Void rollback(TransactionStatus status) throws TransactionException;
}
我们刚刚也说了Spring中PlatformTransactionManager根据不同持久层框架所对应的接口实现类,几个比较常见的如下图所示
比如我们在使用JDBC或者iBatis(就是Mybatis)进行数据持久化操作时,我们的xml配置通常如下:
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
bean>
这个类就定义了事务的一些基本配置,描述了事务策略如何应用到方法上。事务属性包含了5个方面:隔离级别,传播行为,回滚规则,是否只读,事务超时。
public interface TransactionDefinition {
// 返回事务的传播行为
int getPropagationBehavior();
// 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
int getIsolationLevel();
//返回事务的名字
String getName();
// 返回事务必须在多少秒内完成
int getTimeout();
// 返回是否优化为只读事务。
boolean isReadOnly();
}
定义了一个事务可能受到其他并发事务影响的程度
几种并发导致的问题:
不可重复读与幻读的区别
二者是类似的,区别在于不可重复读重点在于修改,幻读在于增删。
几种隔离级别
TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别
TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 未提交读
TransactionDefinition.ISOLATION_READ_COMMITTED: 提交读
TransactionDefinition.ISOLATION_REPEATABLE_READ: 重复读
TransactionDefinition.ISOLATION_SERIALIZABLE: 串行化
为了解决业务层方法之间相互调用的事务问题。
当事务方法被另一个事务方法(确定另一个也必须是事务方法??)调用的时候,必须指定事物应该如何进行传播。
因为方法可能继续在现有事务中运行,也可能开启一个新的事务。
Spring定义了几个表示传播行为的常量,下面按照是否支持当前事务进行分类:
支持当前事务:
不支持当前事务的情况:
TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
其他情况:
以 PROPAGATION_NESTED 启动的事务内嵌于外部事务中(如果存在外部事务的话),此时,内嵌事务并不是一个独立的事务,它依赖于外部事务的存在,只有通过外部的事务提交,才能引起内部事务的提交,嵌套的子事务不能单独提交。如果熟悉 JDBC 中的保存点(SavePoint)的概念,那嵌套事务就很容易理解了,其实嵌套的子事务就是保存点的一个应用,一个事务中可以包括多个保存点,每一个嵌套子事务。另外,外部事务的回滚也会导致嵌套子事务的回滚。
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。
对事务性资源进行只读操作或者读写操作。
事务性资源就是指那些被事务管理的资源,比如数据源,JMS资源,以及自定义的事务性资源等。
如果能标记为只读的话,可以提高事务处理的性能。
定义了哪些异常会导致事务回滚而那些不会。
默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚。
你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样的,你还可以声明事务遇到特定的异常不会滚,即使这些异常是运行期异常。
检查型异常与非检查型异常
继承自Runtime Exception或 Error 的是非检查型异常,而继承自 Exception 的则是检查型异常(当然,Runtime Exception 本身也是 Exception 的子类)。
对非检查型类异常可以不用捕获,而检查型异常则必须用try语句块进行处理或者把异常交给上级方法处理总之就是必须写代码处理它。
TransactionStatus接口用来记录事务的状态,该接口定义了一组方法,用来获取或判断事务的相应状态信息.
PlatformTransactionManager.getTransaction(…) 方法返回一个 TransactionStatus 对象。返回的TransactionStatus 对象可能代表一个新的或已经存在的事务(如果在当前调用堆栈有一个符合条件的事务)。
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事物
boolean hasSavepoint(); // 是否有恢复点
void setRollbackOnly(); // 设置为只回滚
boolean isRollbackOnly(); // 是否为只回滚
boolean isCompleted; // 是否已完成
}
我们在两次转账之间添加一个错误语句(对应银行断电等意外情况),如果这个时候两次转账不能成功,则说明事务配置正确,否则,事务配置不正确。
xml配置
<bean class="org.springframework.transaction.support.DefaultTransactionDefinition" id="transactionDefinition">
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
bean>
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
java配置
@Autowired
TransactionDefinition transactionDefinition;
@Autowired
PlatformTransactionManager transactionManager;
...
public void transfer() {
TransactionStatus status = transactionManager.getTransaction(transactionDefinition);
try {
//本地事务执行逻辑...
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
e.printStackTrace();
}
}
xml配置
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<bean class="org.springframework.transaction.support.TransactionTemplate" id="transactionTemplate">
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="isolationLevelName" value="ISOLATION_DEFAULT"/>
bean>
java
@Autowired
TransactionTemplate transactionTemplate;
public void transfer() {
transactionTemplate.execute(new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus transactionStatus) {
Object result = null;
try {
//本地事务逻辑执行...
//如果顺利执行,参数transactionStatus会自动提交
} catch (Exception e) {
transactionStatus.setRollbackOnly();
result = false;
e.printStackTrace();
}
return result;
}
});
}
顺便说一下,TransactionTemplate是继承于DefaultTransactionDefinition的。
AbstractPlatformTransactionManager中用到了很多ThreadLocal类变量,有空需要研究一下。
xml配置
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="bankdemo*" propagation="REQUIRED"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* cn.kip.service.impl..*.*(..))"/>
aop:config>
java
public void accountMoney () {
//正常业务逻辑执行...
}
xml配置
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
java
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false, timeout = -1)
public void bankdemo() {
//正常业务逻辑执行...
}