在springboot
的自動裝配事務裏面,InfrastructureAdvisorAutoProxyCreator
,TransactionInterceptor
,PlatformTransactionManager
這三個bean都被裝配進來了,InfrastructureAdvisorAutoProxyCreator
已經講過了,就是一個後置處理器,而且優先級不是很高,而是最低,今天的重點是講解後面二者之間在事務的扮演角色。TransactionInterceptor
做爲事務的加強子,扮演着加強處理Spring
事務的核心角色。java
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
是個環繞通知,敲好符合咱們的開啓、提交、回滾事務等操做,源碼分析能夠看出,真正作事情的其實仍是在父類,它有一個執行事務的模版。springboot
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"; } } }
可見它是對PlatformTransactionManager
的一個抽象實現。實現Spring的標準事務工做流
這個基類提供瞭如下工做流程處理:架構
觸發同步回調註冊(若是事務同步是激活的)分佈式
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
等,至關於留好了衆多的鏈接點ide
// 它還實現了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事務,這點是很是重要的。(由於畢竟一個事務內可能有多個連接.