美文网首页
Spring 源码分析之事务2 TransactionStatu

Spring 源码分析之事务2 TransactionStatu

作者: 突突兔007 | 来源:发表于2020-09-14 11:23 被阅读0次

    Spring 源码分析之事务
    Spring 源码分析之事务2 TransactionStatus与TransactionInfo
    Spring 源码分析之事务3 事务的提交与回滚

    Spring事务TransactionStatus接口相关类解析以及TransactionInfo

    首先说一下两个类的作用:
    TransactionStatus以及子类:主要描述当前事务的状态,比如:是否有事务,是否是新事物,事务是否只读;回滚点相关操作等等。这些相关的属性在后面会影响事务的提交。
    TransactionInfo 主要是持有事务的状态,以及上一个TransactionInfo 的一个引用,并与当前线程进行绑定。主要是为了保证当前请求持有的是自己的事务对象,根据自己的事务状态决定事务的提交与否。

    一、TransactionStatus结构图

    该类结构图如下:

    TransactionStatus.jpg

    通过分析我们发现TransactionStatus接口的实现类抽象类AbstractTransactionStatus类主要完成以下功能:

    回滚点相关操作

    • 创建回滚点void createAndHoldSavepoint()
    • 设置回滚点void setSavepoint(@Nullable Object savepoint)
    • 获取回滚点 void getSavepoint()
    • 判断是否有回滚点boolean getSavepoint()
    • 释放回滚点void releaseHeldSavepoint()
    • 回滚到回滚点void rollbackToHeldSavepoint()
      注意:在AbstractTransactionStatus中创建回滚点是需要子类去实现getSavepointManager()方法,默认该方法会抛出异常NestedTransactionNotSupportedException("This transaction does not support savepoints")

    二、AbstractTransactionStatus的子类DefaultTransactionStatus

    image.png
    该类也是spring提供的默认实现类。
    我们可以看到子类实现了getSavepointManager()如下:
        @Override
        protected SavepointManager getSavepointManager() {
            Object transaction = this.transaction;
            if (!(transaction instanceof SavepointManager)) {
                throw new NestedTransactionNotSupportedException(
                        "Transaction object [" + this.transaction + "] does not support savepoints");
            }
            return (SavepointManager) transaction;
        }
    

    如果想要使用事务的回滚相关操作,继承了AbstractTransactionStatus类的子类必须提供实现,否则在使用事务的回滚点相关操作的时候会抛出异常。

    该类还完成了事务相关功能:

    • 获取当前事务Object getTransaction()
    • 是否有激活的事务boolean hasTransaction()
    • 该事务是否是新事务boolean isNewTransaction()
    • 事务是否只读boolean isReadOnly()
    • 返回已为此事务挂起的资源的持有者(如果有)Object getSuspendedResources()

    我们可以全局的看看DefaultTransactionStatus结构图:


    DefaultTransactionStatus.png

    AbstractTransactionStatus 中包含了3条属性:

    private boolean rollbackOnly = false;
    
    private boolean completed = false;
    
    @Nullable
    private Object savepoint;
    
    • 是否回滚

    • 是否完成

    • 保存点对象。

    所以DefaultTransactionStatus对象最终包含的信息有:

    • 是否回滚

    • 是否完成

    • 保存点对象。

    • 事务对象

    • 是否是新事务的boolean

    • 是否是新的同步boolean

    • 是否只读

    • 挂起的资源对象(Object suspendedResources)

    AbstractTransactionStatus 的完成的主要功能:

    1.回滚点相关操作(是否有回滚点、设置回滚点、获取回滚点,创建回滚点)
    2.标记事务已经完成

    三、TransactionInfo

    首先protected TransactionInfo createTransactionIfNecessary这个方法会返回一个TransactionInfo ,即在创建事务的时候,会返回。
    如下:

    protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
                @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
    
            ......
            return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
    

    查看prepareTransactionInfo()方法

    protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
                @Nullable TransactionAttribute txAttr, String joinpointIdentification,
                @Nullable TransactionStatus status) {
    
            TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
            if (txAttr != null) {
                // We need a transaction for this method...
                // The transaction manager will flag an error if an incompatible tx already exists.
                txInfo.newTransactionStatus(status);
            }
            ......
    
            // We always bind the TransactionInfo to the thread, even if we didn't create
            // a new transaction here. This guarantees that the TransactionInfo stack
            // will be managed correctly even if no transaction was created by this aspect.
            txInfo.bindToThread();
            return txInfo;
        }
    

    此方法完成如下功能:

    • 创建TransactionInfo
    • 将当前的DefaultTransactionStatus,上一步我们分析的包含事务相关状态的对象,设置到TransactionInfo里
    • 将新创建好的TransactionInfo绑定到当前线程(ThreadLocal)
    • 返回TransactionInfo#txInfo.bindToThread()方法,如果存在调用多个业务方法,上一个业务方法的事务信息存哪里了,就存bindToThread()方法里。查看方法:
    private void bindToThread() {
                // Expose current TransactionStatus, preserving any existing TransactionStatus
                // for restoration after this transaction is complete.
                this.oldTransactionInfo = transactionInfoHolder.get();
                transactionInfoHolder.set(this);
    }
    

    完整的类如下:
    TransactionInfo 是抽象类TransactionAspectSupport的一个内部类

    这里关注一下
    protected static final class TransactionInfo {
    
       @Nullable
       private final PlatformTransactionManager transactionManager;
    
       @Nullable
       private final TransactionAttribute transactionAttribute;
    
       private final String joinpointIdentification;
    
       @Nullable
       private TransactionStatus transactionStatus;
    
       @Nullable
       private TransactionInfo oldTransactionInfo;
       
       public void newTransactionStatus(@Nullable TransactionStatus status) {
                this.transactionStatus = status;
            }
    
            @Nullable
            public TransactionStatus getTransactionStatus() {
                return this.transactionStatus;
            }
    
            /**
             * Return whether a transaction was created by this aspect,
             * or whether we just have a placeholder to keep ThreadLocal stack integrity.
             */
            public boolean hasTransaction() {
                return (this.transactionStatus != null);
            }
    
            private void bindToThread() {
                // Expose current TransactionStatus, preserving any existing TransactionStatus
                // for restoration after this transaction is complete.
                this.oldTransactionInfo = transactionInfoHolder.get();
                transactionInfoHolder.set(this);
            }
    
            private void restoreThreadLocalStatus() {
                // Use stack to restore old transaction TransactionInfo.
                // Will be null if none was set.
                transactionInfoHolder.set(this.oldTransactionInfo);
            }
            .../
    }       
    

    如果存在一个业务中法中调用多个其他业务,比如:ServiceA的a方法,调用了ServiceB的b方法和ServiceC的c方法。在调用ServiceB的和调用ServiceC的时候当前的事务对象是什么样子的,是和bindToThread()方法有关的,也就是和属性oldTransactionInfo 和持有transactionInfo的当前线程有关。
    这里也可以继续关注一下restoreThreadLocalStatus方法。
    没调用一个业务的时候,每个业务方法都有自己的TransactionInfo,每次执行的时候,都会把当前线程中的TransactionInfo取出来,然后新建自己的TransactionInfo,并在自己的TransactionInfo中,将刚刚取出来的TransactionInfo作为oldTransactionInfo 记录到自己的TransactionInfo中。然后每次执行完一个自己的业务逻辑执行,都会再次执行restoreThreadLocalStatus()方法,也就是将本地线程中的TransactionInfo设置为当前TransactionInfo中的oldTransactionInfo。保证每次执行自己的业务的时候,使用的是自己的TransactionInfo即可,保证事务对象不会发生错乱。

    相关文章

      网友评论

          本文标题:Spring 源码分析之事务2 TransactionStatu

          本文链接:https://www.haomeiwen.com/subject/vwfbektx.html