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

  • 2019 年 10 月 3 日
  • 筆記

摘要:

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事務,這點是非常重要的。(因為畢竟一個事務內可能有多個鏈接.