Spring声明式事务管理源码解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cccmercy/article/details/81584826

核心接口

核心接口
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 {
        // 省略部分代码... 
    }
}
  1. 获取事务属性及事务管理器,这里获取到的事务管理器就是在Spring配置文件中配置的事务管理器实例
  2. 调用事务管理器的getTransaction()方法开启事务,该方法参数是事务属性,返回值是事务状态,并把事务属性、事务状态、事务管理器封装为事务信息(TransactionInfo)返回,便于后续使用
  3. 调用service处理
  4. 若步骤3中抛出异常
    4.1 判断异常是否是满足回滚规则的异常,默认情况下,只有unchecked异常可回滚
    4.2 满足回滚规则,进行后续回滚处理
    4.3 重置事务信息对象
  5. 若步骤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.释放数据库连接

猜你喜欢

转载自blog.csdn.net/cccmercy/article/details/81584826
今日推荐