天天看點

Springboot源碼分析之事務攔截和管理

Springboot源碼分析之事務攔截和管理

摘要:

在springboot的自動裝配事務裡面,InfrastructureAdvisorAutoProxyCreator ,TransactionInterceptor,PlatformTransactionManager這三個bean都被裝配進來了,InfrastructureAdvisorAutoProxyCreator已經講過了,就是一個後置處理器,并且優先級不是很高,而是最低,今天的重點是講解後面兩者之間在事務的扮演角色。TransactionInterceptor作為事務的增強子,扮演着增強處理Spring事務的核心角色。

TransactionInterceptor支撐着整個事務功能的架構,邏輯還是相對複雜的,那麼現在我們切入正題來分析此攔截器是如何實作事務特性的。

Spring事務三大接口

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;
    int PROPAGATION_NESTED = 6;
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = 1;
    int ISOLATION_READ_COMMITTED = 2;
    int ISOLATION_REPEATABLE_READ = 4;
    int ISOLATION_SERIALIZABLE = 8;
    int TIMEOUT_DEFAULT = -1;
}           

TransactionStatus:代表一個事務的具體運作狀态、以及儲存點

public interface TransactionStatus extends SavepointManager, Flushable {
   // 判斷目前的事務是否是新事務
    boolean isNewTransaction();
   // 判斷該事務裡面是否含有儲存點
    boolean hasSavepoint();
     // 這是事務的唯一結果是否進行復原。是以如果你在外層給try catche住不讓事務復原,就會抛出你可能常見的異常
    void setRollbackOnly();

    boolean isRollbackOnly();

    void flush();
   // 不管是commit或者rollback了都算結束了~~~
    boolean isCompleted();
}           

一般都是使用它的實作類DefaultTransactionStatus,它是Spring預設使用的事務狀态。

PlatformTransactionManager:一個高層次的接口,看名字就知道是管理事務的

public interface PlatformTransactionManager {
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;

    void commit(TransactionStatus var1) throws TransactionException;

    void rollback(TransactionStatus var1) throws TransactionException;
}           

事務攔截器

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
    public TransactionInterceptor() {
    }

    public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
        this.setTransactionManager(ptm);
        this.setTransactionAttributes(attributes);
    }

    public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
        this.setTransactionManager(ptm);
        this.setTransactionAttributeSource(tas);
    }

  //最重要的方法,攔截入口
    @Nullable
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
        Method var10001 = invocation.getMethod();
        invocation.getClass();
        return this.invokeWithinTransaction(var10001, targetClass, invocation::proceed);
    }
//省略無關代碼......
}           

我們已經知道了,它是個MethodInterceptor,被事務攔截的方法最終都會執行到此增強器身上。

MethodInterceptor是個環繞通知,敲好符合我們的開啟、送出、復原事務等操作,源碼分析可以看出,真正做事情的其實還是在父類,它有一個執行事務的模版。

TransactionAspectSupport

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
    private static final Object DEFAULT_TRANSACTION_MANAGER_KEY = new Object();
    // currentTransactionStatus() 方法需要使用到它
    private static final ThreadLocal<TransactionAspectSupport.TransactionInfo> transactionInfoHolder = new NamedThreadLocal("Current aspect-driven transaction");
    protected final Log logger = LogFactory.getLog(this.getClass());
    //事務管理器的名稱
    @Nullable
    private String transactionManagerBeanName;
    //事務管理器
    @Nullable
    private PlatformTransactionManager transactionManager;
    //事務屬性源
    @Nullable
    private TransactionAttributeSource transactionAttributeSource;
    @Nullable
    private BeanFactory beanFactory;
    // 因為事務管理器可能也會有多個  是以此處做了一個簡單的緩存~
    private final ConcurrentMap<Object, PlatformTransactionManager> transactionManagerCache = new ConcurrentReferenceHashMap(4);

    public TransactionAspectSupport() {
    }

    @Nullable
    protected static TransactionAspectSupport.TransactionInfo currentTransactionInfo() throws NoTransactionException {
        return (TransactionAspectSupport.TransactionInfo)transactionInfoHolder.get();
    }
    //外部調用此Static方法,可議擷取到目前事務的狀态  進而甚至可議手動來送出、復原事務
    public static TransactionStatus currentTransactionStatus() throws NoTransactionException {
        TransactionAspectSupport.TransactionInfo info = currentTransactionInfo();
        if (info != null && info.transactionStatus != null) {
            return info.transactionStatus;
        } else {
            throw new NoTransactionException("No transaction aspect-managed TransactionStatus in scope");
        }
    }
   //省略無關代碼......
  // 這裡可以發現,若傳入的為Properties  内部是實際使用的是NameMatchTransactionAttributeSource 去比對的,transactionAttributeSource會被覆寫的喲
    public void setTransactionAttributes(Properties transactionAttributes) {
        NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
        tas.setProperties(transactionAttributes);
        this.transactionAttributeSource = tas;
    }
    // 根據方法和目标類來選擇
    public void setTransactionAttributeSources(TransactionAttributeSource... transactionAttributeSources) {
        this.transactionAttributeSource = new CompositeTransactionAttributeSource(transactionAttributeSources);
    }
   //省略無關代碼......
  // 接下來就隻剩我們最為核心的處理事務的模版方法了
   @Nullable
    protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
            final InvocationCallback invocation) throws Throwable {

        // If the transaction attribute is null, the method is non-transactional.
    // 擷取事務屬性源~
        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)) {
            // Standard transaction demarcation with getTransaction and commit/rollback calls.
      // 看是否有必要建立一個事務,根據`事務傳播行為`,做出相應的判斷
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

            Object retVal;
            try {
                // This is an around advice: Invoke the next interceptor in the chain.
                // This will normally result in a target object being invoked.
        //回調方法執行,執行目标方法(原有的業務邏輯)
                retVal = invocation.proceedWithInvocation();
            }
            catch (Throwable ex) {
                // target invocation exception
        // 出現異常了,進行復原(注意:并不是所有異常都會rollback的)
                // 備注:此處若沒有事務屬性   會commit 相容程式設計式事務吧
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            }
            finally {
        //清除資訊
                cleanupTransactionInfo(txInfo);
            }
      // 目标方法完全執行完成後,送出事務~~~
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }
        else {
      //程式設計式事務處理(CallbackPreferringPlatformTransactionManager) 會走這裡 
        // 原理也差不太多,這裡不做詳解~~~~
    
            final ThrowableHolder throwableHolder = new ThrowableHolder();

            // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
            try {
                Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
                    TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
                    try {
                        return invocation.proceedWithInvocation();
                    }
                    catch (Throwable ex) {
                        if (txAttr.rollbackOn(ex)) {
                            // A RuntimeException: will lead to a rollback.
                            if (ex instanceof RuntimeException) {
                                throw (RuntimeException) ex;
                            }
                            else {
                                throw new ThrowableHolderException(ex);
                            }
                        }
                        else {
                            // A normal return value: will lead to a commit.
                            throwableHolder.throwable = ex;
                            return null;
                        }
                    }
                    finally {
                        cleanupTransactionInfo(txInfo);
                    }
                });

                // Check result state: It might indicate a Throwable to rethrow.
                if (throwableHolder.throwable != null) {
                    throw throwableHolder.throwable;
                }
                return result;
            }
            catch (ThrowableHolderException ex) {
                throw ex.getCause();
            }
            catch (TransactionSystemException ex2) {
                if (throwableHolder.throwable != null) {
                    logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                    ex2.initApplicationException(throwableHolder.throwable);
                }
                throw ex2;
            }
            catch (Throwable ex2) {
                if (throwableHolder.throwable != null) {
                    logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                }
                throw ex2;
            }
        }
    }
  // 從容器中找到一個事務管理器
    @Nullable
    protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
        if (txAttr != null && this.beanFactory != null) {
          // qualifier 就在此處發揮作用了,他就相當于BeanName
            String qualifier = txAttr.getQualifier();
            if (StringUtils.hasText(qualifier)) {
              // 根據此名稱 以及PlatformTransactionManager.class 去容器内找
                return this.determineQualifiedTransactionManager(this.beanFactory, qualifier);  // 若沒有指定qualifier   那再看看是否指定了 transactionManagerBeanName
            } else if (StringUtils.hasText(this.transactionManagerBeanName)) {
              
                return this.determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
            } else {
              // 若都沒指定,那就不管了。直接根據類型去容器裡找 getBean(Class)
        // 此處:若容器内有兩個PlatformTransactionManager ,那就鐵定會報錯啦~~~
    
                PlatformTransactionManager defaultTransactionManager = this.getTransactionManager();
                if (defaultTransactionManager == null) {
                    defaultTransactionManager = (PlatformTransactionManager)this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
                    if (defaultTransactionManager == null) {
                        defaultTransactionManager = (PlatformTransactionManager)this.beanFactory.getBean(PlatformTransactionManager.class);
                        this.transactionManagerCache.putIfAbsent(DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
                    }
                }

                return defaultTransactionManager;
            }
        } else {
          // 如果這兩個都沒配置,是以肯定是手動設定了PlatformTransactionManager的,那就直接傳回即可
            return this.getTransactionManager();
        }
    }

    private PlatformTransactionManager determineQualifiedTransactionManager(BeanFactory beanFactory, String qualifier) {
        PlatformTransactionManager txManager = (PlatformTransactionManager)this.transactionManagerCache.get(qualifier);
        if (txManager == null) {
            txManager = (PlatformTransactionManager)BeanFactoryAnnotationUtils.qualifiedBeanOfType(beanFactory, PlatformTransactionManager.class, qualifier);
            this.transactionManagerCache.putIfAbsent(qualifier, txManager);
        }

        return txManager;
    }

    private String methodIdentification(Method method, @Nullable Class<?> targetClass, @Nullable TransactionAttribute txAttr) {
        String methodIdentification = this.methodIdentification(method, targetClass);
        if (methodIdentification == null) {
            if (txAttr instanceof DefaultTransactionAttribute) {
                methodIdentification = ((DefaultTransactionAttribute)txAttr).getDescriptor();
            }

            if (methodIdentification == null) {
                methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
            }
        }

        return methodIdentification;
    }

    @Nullable
    protected String methodIdentification(Method method, @Nullable Class<?> targetClass) {
        return null;
    }
// 若有需要 建立一個TransactionInfo (具體的事務從事務管理器裡面getTransaction())
    protected TransactionAspectSupport.TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
      //指派
        if (txAttr != null && ((TransactionAttribute)txAttr).getName() == null) {
            txAttr = new DelegatingTransactionAttribute((TransactionAttribute)txAttr) {
                public String getName() {
                    return joinpointIdentification;
                }
            };
        }
// 從事務管理器裡,通過txAttr拿出來一個TransactionStatus
        TransactionStatus status = null;
        if (txAttr != null) {
            if (tm != null) {
                status = tm.getTransaction((TransactionDefinition)txAttr);
            } else if (this.logger.isDebugEnabled()) {
                this.logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured");
            }
        }
// 通過TransactionStatus 等,轉換成一個通用的TransactionInfo
        return this.prepareTransactionInfo(tm, (TransactionAttribute)txAttr, joinpointIdentification, status);
    }
    protected TransactionAspectSupport.TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, String joinpointIdentification, @Nullable TransactionStatus status) {
      //構造一個TransactionInfo
        TransactionAspectSupport.TransactionInfo txInfo = new TransactionAspectSupport.TransactionInfo(tm, txAttr, joinpointIdentification);
        if (txAttr != null) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
            }
           // 設定事務狀态
            txInfo.newTransactionStatus(status);
        } else if (this.logger.isTraceEnabled()) {
            this.logger.trace("No need to create transaction for [" + joinpointIdentification + "]: This method is not transactional.");
        }
// 這句話是最重要的,把生成的TransactionInfo并綁定到目前線程的ThreadLocal
        txInfo.bindToThread();
        return txInfo;
    }
//比較簡單  隻用用事務管理器送出事務即可~~~  具體的實作邏輯在事務管理器的commit實作裡~~
    protected void commitTransactionAfterReturning(@Nullable TransactionAspectSupport.TransactionInfo txInfo) {
        if (txInfo != null && txInfo.getTransactionStatus() != null) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
            }

            txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
        }

    }

    protected void completeTransactionAfterThrowing(@Nullable TransactionAspectSupport.TransactionInfo txInfo, Throwable ex) {
        if (txInfo != null && txInfo.getTransactionStatus() != null) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex);
            }
// 如果有事務屬性了,那就調用rollbackOn看看這個異常需不需要復原
            if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
                try {
                    txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
                } catch (TransactionSystemException var6) {
                    this.logger.error("Application exception overridden by rollback exception", ex);
                    var6.initApplicationException(ex);
                    throw var6;
                } catch (Error | RuntimeException var7) {
                    this.logger.error("Application exception overridden by rollback exception", ex);
                    throw var7;
                }
            } else {
              // 程式設計式事務沒有事務屬性,那就commit吧
                try {
                    txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
                } catch (TransactionSystemException var4) {
                    this.logger.error("Application exception overridden by commit exception", ex);
                    var4.initApplicationException(ex);
                    throw var4;
                } catch (Error | RuntimeException var5) {
                    this.logger.error("Application exception overridden by commit exception", ex);
                    throw var5;
                }
            }
        }

    }

    protected void cleanupTransactionInfo(@Nullable TransactionAspectSupport.TransactionInfo txInfo) {
        if (txInfo != null) {
            txInfo.restoreThreadLocalStatus();
        }

    }

    private static class ThrowableHolderException extends RuntimeException {
        public ThrowableHolderException(Throwable throwable) {
            super(throwable);
        }

        public String toString() {
            return this.getCause().toString();
        }
    }

    private static class ThrowableHolder {
        @Nullable
        public Throwable throwable;

        private ThrowableHolder() {
        }
    }

    @FunctionalInterface
    protected interface InvocationCallback {
        Object proceedWithInvocation() throws Throwable;
    }

    protected final class TransactionInfo {
      // 目前事務  的事務管理器
        @Nullable
        private final PlatformTransactionManager transactionManager;
      // 目前事務  的事務屬性
        @Nullable
        private final TransactionAttribute transactionAttribute;
      //joinpoint辨別
        private final String joinpointIdentification;
      //目前事務    的TransactionStatus
        @Nullable
        private TransactionStatus transactionStatus;
      // 重點就是這個oldTransactionInfo字段
          // 這個字段儲存了目前事務所在的`父事務`上下文的引用,構成了一個鍊,準确的說是一個有向無環圖
    
        @Nullable
        private TransactionAspectSupport.TransactionInfo oldTransactionInfo;

        public TransactionInfo(@Nullable PlatformTransactionManager transactionManager, @Nullable TransactionAttribute transactionAttribute, String joinpointIdentification) {
            this.transactionManager = transactionManager;
            this.transactionAttribute = transactionAttribute;
            this.joinpointIdentification = joinpointIdentification;
        }

        public PlatformTransactionManager getTransactionManager() {
            Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
            return this.transactionManager;
        }

        @Nullable
        public TransactionAttribute getTransactionAttribute() {
            return this.transactionAttribute;
        }

        public String getJoinpointIdentification() {
            return this.joinpointIdentification;
        }
        //注意這個方法名,新的一個事務status
        public void newTransactionStatus(@Nullable TransactionStatus status) {
            this.transactionStatus = status;
        }

        @Nullable
        public TransactionStatus getTransactionStatus() {
            return this.transactionStatus;
        }

        public boolean hasTransaction() {
            return this.transactionStatus != null;
        }
         //綁定目前正在處理的事務的所有資訊到ThreadLocal
        private void bindToThread() {
          // 老的事務  先從線程中拿出來,再把新的(也就是目前)綁定進去~~~~~~
            this.oldTransactionInfo = (TransactionAspectSupport.TransactionInfo)TransactionAspectSupport.transactionInfoHolder.get();
            TransactionAspectSupport.transactionInfoHolder.set(this);
        }
        //目前事務處理完之後,恢複父事務上下文
        private void restoreThreadLocalStatus() {
            TransactionAspectSupport.transactionInfoHolder.set(this.oldTransactionInfo);
        }

        public String toString() {
            return this.transactionAttribute != null ? this.transactionAttribute.toString() : "No transaction";
        }
    }
}           

事務管理器

file

AbstractPlatformTransactionManager

可見它是對PlatformTransactionManager的一個抽象實作。實作Spring的标準事務工作流

這個基類提供了以下工作流程處理:

确定如果有現有的事務;

應用适當的傳播行為;

如果有必要暫停和恢複事務;

送出時檢查rollback-only标記;

應用适當的修改當復原(實際復原或設定rollback-only);

觸發同步回調注冊(如果事務同步是激活的)

public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {

    //始終激活事務同步(請參閱事務的傳播屬性~)
    public static final int SYNCHRONIZATION_ALWAYS = 0;
    //僅對實際事務(即,不針對由傳播導緻的空事務)激活事務同步\不支援現有後端事務
    public static final int SYNCHRONIZATION_ON_ACTUAL_TRANSACTION = 1;
    //永遠不激活事務同步
    public static final int SYNCHRONIZATION_NEVER = 2;

    // 相當于把本類的所有的public static final的變量都收集到此處~~~~
    private static final Constants constants = new Constants(AbstractPlatformTransactionManager.class);

    // ===========預設值
    private int transactionSynchronization = SYNCHRONIZATION_ALWAYS;
    // 事務預設的逾時時間  為-1表示不逾時
    private int defaultTimeout = TransactionDefinition.TIMEOUT_DEFAULT;
    //Set whether nested transactions are allowed. Default is "false".
    private boolean nestedTransactionAllowed = false;
    // Set whether existing transactions should be validated before participating(參與、加入)
    private boolean validateExistingTransaction = false;
    
    //設定是否僅在參與事務`失敗後`将 現有事務`全局`标記為復原  預設值是true 需要注意~~~
    // 表示隻要你的事務失敗了,就标記此事務為rollback-only 表示它隻能給與復原  而不能再commit或者正常結束了
    // 這個調用者經常會犯的一個錯誤就是:上層事務service抛出異常了,自己把它給try住,并且并且還不throw,那就肯定會報錯的:
    // 報錯資訊:Transaction rolled back because it has been marked as rollback-only
    // 當然喽,這個屬性強制不建議設定為false~~~~~~
    private boolean globalRollbackOnParticipationFailure = true;
    // 如果事務被全局标記為僅復原,則設定是否及早失敗~~~~
    private boolean failEarlyOnGlobalRollbackOnly = false;
    // 設定在@code docommit調用失敗時是否應執行@code dorollback 通常不需要,是以應避免
    private boolean rollbackOnCommitFailure = false;
    
    // 我們發現使用起來有點枚舉的意思了,特别是用XML配置的時候  非常像枚舉的使用~~~~~~~
    // 這也是Constants的重要意義~~~~
    public final void setTransactionSynchronizationName(String constantName) {
        setTransactionSynchronization(constants.asNumber(constantName).intValue());
    }
    public final void setTransactionSynchronization(int transactionSynchronization) {
        this.transactionSynchronization = transactionSynchronization;
    }
    //... 省略上面所有字段的一些get/set方法~~~

    // 最為重要的一個方法,根據實物定義,擷取到一個事務TransactionStatus 
    @Override
    public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
        //doGetTransaction()方法是抽象方法,具體的實作由具體的事務處理器提供(下面會以DataSourceTransactionManager為例子)
        Object transaction = doGetTransaction();

        //如果沒有配置事務屬性,則使用預設的事務屬性
        if (definition == null) {
            definition = new DefaultTransactionDefinition();
        }

        //檢查目前線程是否存在事務  isExistingTransaction此方法預設傳回false  但子類都複寫了此方法
        if (isExistingTransaction(transaction)) {
            // handleExistingTransaction方法為處理已經存在事務的情況
            // 這個方法的實作也很複雜,總之還是對一些傳播屬性進行解析,各種情況的考慮~~~~~ 如果有新事務産生 doBegin()就會被調用~~~~
            return handleExistingTransaction(definition, transaction, debugEnabled);
        }

        // 逾時時間的簡單校驗~~~~
        if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
            throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
        }

        // 處理事務屬性中配置的事務傳播特性==============
    
        // PROPAGATION_MANDATORY 如果已經存在一個事務,支援目前事務。如果沒有一個活動的事務,則抛出異常
        if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
            throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");
        }
    
        //如果事務傳播特性為required、required_new或nested
        else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
                definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
                definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
                
            // 挂起,但是doSuspend()由子類去實作~~~
            // 挂起操作,觸發相關的挂起注冊的事件,把目前線程事物的所有屬性都封裝好,放到一個SuspendedResourcesHolder
            // 然後清空清空一下`目前線程事務`
            SuspendedResourcesHolder suspendedResources = suspend(null);

            // 此處,開始建立事務~~~~~
            try {
                boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

                // //建立一個新的事務狀态  就是new DefaultTransactionStatus()  把個屬性都指派上
                DefaultTransactionStatus status = newTransactionStatus(
                        definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
                // 開始事務,抽象方法,由子類去實作~
                doBegin(transaction, definition);
                //初始化和同步事務狀态    是TransactionSynchronizationManager這個類  它内部維護了很多的ThreadLocal
                prepareSynchronization(status, definition);
                return status;
            }
            catch (RuntimeException | Error ex) {
                //重新開始 doResume由子類去實作
                resume(null, suspendedResources);
                throw ex;
            }
        }
        // 走到這裡  傳播屬性就是不需要事務的  那就直接建立一個
        else {
            boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
            // 這個方法相當于先newTransactionStatus,再prepareSynchronization這兩步~~~
            // 顯然和上面的差別是:中間不回插入調用doBegin()方法,因為沒有事務  begin個啥~~
            return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
        }
    }


    // 再看看commit方法
    @Override
    public final void commit(TransactionStatus status) throws TransactionException {
        //如果是一個已經完成的事物,不可重複送出
        if (status.isCompleted()) {
            throw new IllegalTransactionStateException("Transaction is already completed - do not call commit or rollback more than once per transaction");
        }

        DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
        // 如果已經标記為了需要復原,那就執行復原吧
        if (defStatus.isLocalRollbackOnly()) {
            processRollback(defStatus, false);
            return;
        }

        //  shouldCommitOnGlobalRollbackOnly這個預設值是false,目前隻有JTA事務複寫成true了
        // isGlobalRollbackOnly:是否标記為了全局的RollbackOnly
        if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
            processRollback(defStatus, true);
            return;
        }
        // 送出事務   這裡面還是挺複雜的,會考慮到還原點、新事務、事務是否是rollback-only之類的~~
        processCommit(defStatus);
    }

    // rollback方法  裡面doRollback方法交給子類去實作~~~
    @Override
    public final void rollback(TransactionStatus status) throws TransactionException {
        DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
        processRollback(defStatus, false);
    }
}           

從這個抽象類源碼分析可以看出,它絕對是一個非常非常典型的模版實作,各個方法實作都是這樣。自己先提供實作模版,很多具體的實作方案都開放給子類,比如begin,suspend, resume,commit,rollback等,相當于留好了衆多的連接配接點

DataSourceTransactionManager

// 它還實作了ResourceTransactionManager接口,提供了getResourceFactory()方法
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean {
    // 顯然它管理的就是DataSource  而JTA分布式事務管理可能就是各種各樣的資料源了
    @Nullable
    private DataSource dataSource;
    // 不要強制标記為ReadOnly
    private boolean enforceReadOnly = false;

    // JDBC預設是允許内嵌的事務的
    public DataSourceTransactionManager() {
        setNestedTransactionAllowed(true);
    }
    public DataSourceTransactionManager(DataSource dataSource) {
        this();
        setDataSource(dataSource);
        // 它自己的InitializingBean也是做了一個簡單的校驗而已~~~
        afterPropertiesSet();
    }

    // 手動設定資料源
    public void setDataSource(@Nullable DataSource dataSource) {
        // 這步處理有必要
        // TransactionAwareDataSourceProxy是對dataSource 的包裝
        if (dataSource instanceof TransactionAwareDataSourceProxy) {
            this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
        } else {
            this.dataSource = dataSource;
        }
    }

    //Return the JDBC DataSource
    @Nullable
    public DataSource getDataSource() {
        return this.dataSource;
    }
    // @since 5.0 Spring5.0提供的方法   其實還是調用的getDataSource()  判空了而已
    protected DataSource obtainDataSource() {
        DataSource dataSource = getDataSource();
        Assert.state(dataSource != null, "No DataSource set");
        return dataSource;
    }
    // 直接傳回的資料源~~~~
    @Override
    public Object getResourceFactory() {
        return obtainDataSource();
    }
    ...
    // 這裡傳回的是一個`DataSourceTransactionObject`
    // 它是一個`JdbcTransactionObjectSupport`,是以它是SavepointManager、實作了SmartTransactionObject接口
    @Override
    protected Object doGetTransaction() {
        DataSourceTransactionObject txObject = new DataSourceTransactionObject();
        txObject.setSavepointAllowed(isNestedTransactionAllowed());
        // 這個擷取有意思~~~~相當于按照線程來的~~~
        ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
        txObject.setConnectionHolder(conHolder, false);
        return txObject;
    }

    // 檢查目前事務是否active
    @Override
    protected boolean isExistingTransaction(Object transaction) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
    }


    // 這是一個核心内容了,裡面邏輯需要分析分析~~~
    @Override
    protected void doBegin(Object transaction, TransactionDefinition definition) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        Connection con = null;

        try {
            if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
                // 從DataSource裡擷取一個連接配接(這個DataSource一般是有連接配接池的~~~)
                Connection newCon = obtainDataSource().getConnection();
                // 把這個連結用ConnectionHolder包裝一下~~~
                txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
            }

            txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
            con = txObject.getConnectionHolder().getConnection();
            
            // 設定isReadOnly、設定隔離界别等~
            Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
            txObject.setPreviousIsolationLevel(previousIsolationLevel);

            // 這裡非常的關鍵,先看看Connection 是否是自動送出的
            // 如果是 就con.setAutoCommit(false)  要不然資料庫預設沒執行一條SQL都是一個事務,就沒法進行事務的管理了
            if (con.getAutoCommit()) {
                txObject.setMustRestoreAutoCommit(true);
                con.setAutoCommit(false);
            }
            // ====是以從這後面,通過此Connection執行的所有SQL語句隻要沒有commit就都不會送出給資料庫的=====
            
            // 這個方法特别特别有意思   它自己`Statement stmt = con.createStatement()`拿到一個Statement
            // 然後執行了一句SQL:`stmt.executeUpdate("SET TRANSACTION READ ONLY");`
            // 是以,是以:如果你僅僅隻是查詢。把事務的屬性設定為readonly=true  Spring對幫你對SQl進行優化的
            // 需要注意的是:readonly=true 後,隻能讀,不能進行dml操作)(隻能看到設定事物前資料的變化,看不到設定事物後資料的改變)
            prepareTransactionalConnection(con, definition);
            txObject.getConnectionHolder().setTransactionActive(true);

            int timeout = determineTimeout(definition);
            if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
                txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
            }

            // Bind the connection holder to the thread.
            // 這一步:就是把目前的連結 和目前的線程進行綁定~~~~
            if (txObject.isNewConnectionHolder()) {
                TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
            }
        } catch (Throwable ex) {
            // 如果是新建立的連結,那就釋放~~~~
            if (txObject.isNewConnectionHolder()) {
                DataSourceUtils.releaseConnection(con, obtainDataSource());
                txObject.setConnectionHolder(null, false);
            }
            throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
        }
    }

    // 真正送出事務
    @Override
    protected void doCommit(DefaultTransactionStatus status) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
        // 拿到連結  然後直接就commit了   
        Connection con = txObject.getConnectionHolder().getConnection();
        try {
            con.commit();
        } catch (SQLException ex) {
            throw new TransactionSystemException("Could not commit JDBC transaction", ex);
        }
    }
    //doRollback()方法也類似  這裡不再細說
}           

小結:

事務屬性readonly=true後,隻能讀操作)(隻能看到設定事物前資料的變化,看不到設定事物後資料的改變) 但是通過源碼我發現,你隻設定@Transactional(readOnly = true)這樣是不夠的,還必須在配置DataSourceTransactionManager的時候,來這麼一句dataSourceTransactionManager.setEnforceReadOnly(true),最終才會對你的隻讀事務進行優化~~~~

其實如果僅僅隻是設定@Transactional(readOnly = true),最終會把這個Connection設定為隻讀:con.setReadOnly(true); 它表示将此連接配接設定為隻讀模式,作為驅動程式啟用資料庫優化的提示。 将連結設定為隻讀模式通知資料庫後,資料庫會對做自己的隻讀優化。但是,這對資料庫而言不一定對于資料庫而言這就是readonly事務,這點是非常重要的。(因為畢竟一個事務内可能有多個連結.

原文位址

https://www.cnblogs.com/qinzj/p/11437148.html