核心接口
1. PlatformTransactionManager
:事务管理器顶级接口:各持久化框架要想接入Spring的事务管理,必须自行提供该接口实现
2. TransactionDefinition
:事务的属性顶级接口:其实现类封装事务隔离级别、事务传播性、只读性等信息
3. TransactionStatus
:事务状态顶级接口:其实现类封装事务状态信息
声明式事务流程
说明 :以下流程基于JDBC事务管理,Hibernate或Mybatis事务流程与本流程类似。若流程详解中代码片段有多段,均按执行时调用关系贴出,关键代码处均加上了注释,从上到下阅读即可。
Spring数据源及事务配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<context:component-scan base-package="com.mercy">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!-- 数据源管理器-->
<bean id="dataSource" class="com.mercy.dynamic.DynamicDataSource"></bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置声明式事务-->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<!-- 配置编程式事务 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"></property>
</bean>
</beans>
TransactionInterceptor中的流程
代码:
(TransactionInterceptor)
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
// 获取事务属性及事务管理器
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// 开启事务,返回事务信息对象(包含事务属性、事务管理器、事务状态信息)
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// proceedWithInvocation方法中,最终调用service处理逻辑
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 出现异常,继续判断是否需要回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 重置事务信息对象
cleanupTransactionInfo(txInfo);
}
// 调用service处理后正常返回,进行事务提交
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
// 省略部分代码...
}
}
- 获取事务属性及事务管理器,这里获取到的事务管理器就是在Spring配置文件中配置的事务管理器实例
- 调用事务管理器的getTransaction()方法开启事务,该方法参数是事务属性,返回值是事务状态,并把事务属性、事务状态、事务管理器封装为事务信息(TransactionInfo)返回,便于后续使用
- 调用service处理
- 若步骤3中抛出异常
4.1 判断异常是否是满足回滚规则的异常,默认情况下,只有unchecked异常可回滚
4.2 满足回滚规则,进行后续回滚处理
4.3 重置事务信息对象 - 若步骤3中正常返回
5.1 重置事务信息对象
5.2 开始进行提交事务
事务管理器中核心流程 –> 事务拦截器中各个流程的细节
由于我配置的是JDBC事务管理器,这里也是针对此管理器叙述
1. 开启事务 –> 事务拦截器的流程2
在事务管理器的细节
1.1 从数据源中获取数据库连接
1.2 关闭自动提交
1.3 把获取到的数据库连接绑定到当前线程
2. 提交事务 –> 事务拦截器的流程5.2
在事务管理器的细节
2.1 从事务状态对象中获取数据库连接
2.2 提交事务
3. 回滚事务 –> 事务拦截器的流程4.2
在事务管理器的细节
3.1 从事务状态对象中获取数据库连接
3.2 回滚事务
4. 事务完成后的清理工作,在事务回滚或者事务提交后都会执行,具体时机见下面的详解代码片段
4.1 解绑与当前线程绑定的数据源
4.2 重置此次事务使用数据库连接
4.3 释放此次事务使用的数据库连接,若没有使用数据库连接池,否则直接关闭,否则把数据库连接归还给连接池
TransactionInterceptor流程2详解
代码1:
(TransactionInterceptor)
protected TransactionInfo createTransactionIfNecessary(
PlatformTransactionManager tm, TransactionAttribute txAttr, final String joinpointIdentification) {
// 省略部分代码...
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
// 通过配置的事务管理器开启事务,返回事务状态
status = tm.getTransaction(txAttr);
}
else {
// 省略部分代码...
}
}
// 把事务属性、事务管理器、事务状态封装为事务信息返回
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
代码2:
(DataSourceTransactionManager)
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
Object transaction = doGetTransaction();
// 省略部分代码...
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 开启事务
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
// 省略部分代码...
}
代码3:
(DataSourceTransactionManager)
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (txObject.getConnectionHolder() == null ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// 通过数据源获取数据库连接
Connection newCon = this.dataSource.getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
// 省略部分代码...
// 关闭自动提交
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
// 省略部分代码...
// 把数据库连接绑定到当前线程
// Bind the connection holder to the thread.
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
}
// 省略部分代码...
}
执行至此然后返回,整个事务开启完成。这里开启事务的核心就是从配置的数据源中获取一个数据库连接,关闭自动提交,然后把这个数据库连接绑定到当前线程,供后续使用
TransactionInterceptor流程4详解(调用service过程中出异常)
代码1:
(TransactionInterceptor)
protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.hasTransaction()) {
// 省略部分代码...
// 判断异常是否是满足回滚规则的异常,默认情况下,只有unchecked异常可回滚
if (txInfo.transactionAttribute.rollbackOn(ex)) {
try {
// 从事务信息对象获取事务管理器对象,进行事务回滚
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
// 省略部分代码...
}
else {
// 省略部分代码...
}
}
}
这里核心就是判断异常是否满足回滚规则,若满足则进行后续回滚
代码2:
(DataSourceTransactionManager)
private void processRollback(DefaultTransactionStatus status) {
try {
try {
triggerBeforeCompletion(status);
if (status.hasSavepoint()) {
// 省略部分代码...
}
else if (status.isNewTransaction()) {
// 省略部分代码...
// 通过配置的事务管理器进行回滚
doRollback(status);
}
// 省略部分代码...
}
// 省略部分代码...
}
finally {
// 执行回滚的后需清理工作
cleanupAfterCompletion(status);
}
}
这里先通过事务管理器进行回滚,回滚操作完成后进行清理工作,清理细节见后续代码4
代码3:
(DataSourceTransactionManager)
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
// 获取之前已开启事务的数据库连接
Connection con = txObject.getConnectionHolder().getConnection();
try {
// 回滚
con.rollback();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
}
}
这里获取之前开启事务的数据库连接进行回滚
代码4:
(DataSourceTransactionManager)
protected void doCleanupAfterCompletion(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
// 解绑与当前线程绑定的数据源
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.unbindResource(this.dataSource);
}
// 重置数据库连接
Connection con = txObject.getConnectionHolder().getConnection();
try {
if (txObject.isMustRestoreAutoCommit()) {
con.setAutoCommit(true);
}
DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
}
catch (Throwable ex) {
logger.debug("Could not reset JDBC Connection after transaction", ex);
}
if (txObject.isNewConnectionHolder()) {
if (logger.isDebugEnabled()) {
logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
}
// 释放数据库连接
DataSourceUtils.releaseConnection(con, this.dataSource);
}
txObject.getConnectionHolder().clear();
}
回滚后的清理工作:1.解绑与当前线程绑定的数据库连接 2.重置数据库连接 3.释放数据库连接
TransactionInterceptor流程5详解(调用service过程正常返回)
代码1:
(TransactionInterceptor)
protected void commitTransactionAfterReturning(TransactionInfo txInfo) {
if (txInfo != null && txInfo.hasTransaction()) {
// 从事务信息对象中获取事务管理器,进行后续提交
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
代码2:
(DataSourceTransactionManager)
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
// 省略部分代码...
if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
// 执行提交
doCommit(status);
}
// 省略部分代码...
}
// 省略部分代码...
}
finally {
// 提交后的清理工作
cleanupAfterCompletion(status);
}
}
事务管理器进行事务提交,然后进行清理工作
代码3:
(DataSourceTransactionManager)
protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
// 获取之前开启事务的数据库连接
Connection con = txObject.getConnectionHolder().getConnection()
try {
// 提交事务
con.commit();
}
// 省略部分代码...
}
获取之前开启了事务的数据库连接进行提交
代码4:
(DataSourceTransactionManager)
protected void doCleanupAfterCompletion(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
// 解绑与当前线程绑定的数据源
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.unbindResource(this.dataSource);
}
// 重置数据库连接
Connection con = txObject.getConnectionHolder().getConnection();
try {
if (txObject.isMustRestoreAutoCommit()) {
con.setAutoCommit(true);
}
DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
}
catch (Throwable ex) {
logger.debug("Could not reset JDBC Connection after transaction", ex);
}
if (txObject.isNewConnectionHolder()) {
if (logger.isDebugEnabled()) {
logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
}
// 释放数据库连接
DataSourceUtils.releaseConnection(con, this.dataSource);
}
txObject.getConnectionHolder().clear();
}
提交后的清理工作:1.解绑与当前线程绑定的数据库连接 2.重置数据库连接 3.释放数据库连接