Spring声明式事务Transactional的执行原理

前言:

众所周知, Spring实现事务控制是在方法上添加注解Transactional来实现的。例如: @Transactional(rollbackFor = Exception.class) 当我们的业务逻辑代码抛出异常时,Spring 会捕获到异常,并检验其是否在rollbackFor中【默认是运行时异常】,并判断是否执行回滚操作。

技术先知:

当我们在了解Spring事务控制原理之前先来了解一下Spring控制事务常用类:

  1. PlatformTransactionManager接口,事务管理定义接口,实现Spring事务事务管理,该接口需要被实现:
  2. TransactionDefinition 事务定义:包含事务的隔离级别、传播属性等等:
  3. TransactionStatus : 事务的状态。

PlatformTransactionManager:

public interface PlatformTransactionManager {

    // 创建新事务或返回当前事务(事务嵌套时,根据隔离级别不同,返回不同)
    TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;

    // 提交事务
    void commit(TransactionStatus status) throws TransactionException;

    // 回滚事务
    void rollback(TransactionStatus status) throws TransactionException;

}

TransactionDefinition

public interface TransactionDefinition {

    /**
     * 类型: 支持当前事务
     * 解释: 如果当前没有事务,就新建一个事务,如果有事务,就加入其中
     */
    int PROPAGATION_REQUIRED = 0;

    /**
     * 类型: 支持当前事务
     * 解释: 支持当前事务,如果没有事务,则以非事务的形式执行
     */
    int PROPAGATION_SUPPORTS = 1;

    /**
     * 类型: 支持当前事务
     * 解释: 支持当前事务,如果没有事务,就抛出异常
     */
    int PROPAGATION_MANDATORY = 2;

    /**
     * 类型: 不支持当前事务
     * 解释: 新建事务,如果存在事务,就将事务挂起,新建一个事务
     */
    int PROPAGATION_REQUIRES_NEW = 3;

    /**
     * 类型: 不支持当前事务
     * 解释: 以非事务的方式执行,当前存在事务,就把当前事务挂起
     */
    int PROPAGATION_NOT_SUPPORTED = 4;

    /**
     * 类型: 不支持当前事务
     * 解释: 以非事务的方式执行,如果当前有事务,则抛出异常
     */
    int PROPAGATION_NEVER = 5;

    /**
     * 类型: 事务嵌套
     * 解释: 如果当前存在事务,则在嵌套事务中执行;如果当前没有事务,则执行与Propagation. REQUIRED类似的操作
     */
    int PROPAGATION_NESTED = 6;

    /**
     *  类型 :Default
     * 解释: 默认的事务隔离级别,默认是用数据库的事务隔离级别
     */
    int ISOLATION_DEFAULT = -1;

    /**
     *  类型:未提交读
     * 解释: 脏读,不可重复读、幻读都存在
     */
    int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;

    /**
     * 类型: 已提交读
     * 解释: 避免脏读,但是存在不可重复读,幻读
     */
    int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;

    /**
     * 类型: 可重复读
     * 解释: 避免脏读和不可重复读,但是有幻读的可能
     */
    int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;

    /**
     * 类型: 串行化
     * 解释: 避免以上所有读的问题
     */
    int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;


    int TIMEOUT_DEFAULT = -1;

    int getPropagationBehavior();

    int getIsolationLevel();

    int getTimeout();

    boolean isReadOnly();

    String getName();

}

TransactionStatus

public interface TransactionStatus extends SavepointManager, Flushable {

    // 是否是新事务
    boolean isNewTransaction();

    // 是否有保存节点
    boolean hasSavepoint();

    // 仅设置事务回滚
    void setRollbackOnly();

    // 是否被标记仅设置事务回滚
    boolean isRollbackOnly();

    // 刷新到数据存储区
    @Override
    void flush();

    // 返回此事务是否已完成 【提交或回滚】
    boolean isCompleted();

}

运行时源码:

上述是关于Spring 对事务管理的制定的相关规则,那到我们配置了Transactional 注解后,Spring究竟执行了那些代码,怎么实现的 具体功能,那我们来具体看一下 TransactionInterceptor 和 TransactionAspectSupport 【TransactionInterceptor 继承 TransactionAspectSupport 】 :
org.springframework.transaction.interceptor.TransactionInterceptor#invoke:

public Object invoke(final MethodInvocation invocation) throws Throwable {
		// 业务逻辑对象
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		//  调用 TransactionAspectSupport  对象中的方法
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction:

@Nullable
    protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
                                             final InvocationCallback invocation) throws Throwable {

        // 1. 获取事务管理器
        TransactionAttributeSource tas = getTransactionAttributeSource();
        final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
        final PlatformTransactionManager tm = determineTransactionManager(txAttr);
        final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

        if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
            // 开启事务,获取到事务对象,并设置连接 AutoCommit = False
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
            Object retVal = null;
            try {
                // 执行我们的业务逻辑代码 Service
                retVal = invocation.proceedWithInvocation();
            }
            catch (Throwable ex) {
                // 捕获异常,判断时候需要回滚,并将异常继续抛出。
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            }
            finally {
                // 重置事务对象信息
                cleanupTransactionInfo(txInfo);
            }
            // 无异常,提交事务
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }

        else {
           // 省略....
        }
    }

根据 invokeWithinTransaction 可以看出整个事务控制、和业务逻辑代码的调用 在其方法内已全部完成,由于Spring源码的黑深林过于复杂,本篇博文没有去过多的深入源码,有兴趣的小伙伴可以 Debug 向源码中仔细阅读,Spring 事务源码简单理解也就是:

  1. 获取事务控制信息 :Transaction tx=session.getTransaction();
  2. 开启事务,设置自动提交False:session.beginTransaction();
  3. 提交事务:tx.commit();
  4. 回滚事务:tx.rollback();

需要注意的是,事务的回滚与提交是由数据库来实现的,Spring只不过调用其方法而已。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值