對於第二個問題,涉及到事務的傳播級別,定義以下:spring
PROPAGATION_REQUIRED-- 若是當前沒有事務,就新建一個事務。這是最多見的選擇。
PROPAGATION_SUPPORTS-- 若是當前沒有事務,就以非事務方式執行。
PROPAGATION_MANDATORY-- 若是當前沒有事務,就拋出異常。
PROPAGATION_REQUIRES_NEW--新建事務,若是當前存在事務,把當前事務掛起。
PROPAGATION_NOT_SUPPORTED--以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。
PROPAGATION_NEVER--以非事務方式執行,若是當前存在事務,則拋出異常。 數據庫
在開啓事務以前,正常狀況下須要作兩個事情jvm
一:獲取當前事務上下文信息分佈式
二:獲取將要開啓事務的傳播屬性spa
根據以上兩個信息,來判斷程序的處理方式,具體方式以下:debug
而處理流程則是以下:設計
其中上圖標中英文簡稱對應的事務傳播屬性以下:日誌
RE: PROPAGATION_REQUIRED-- 若是當前沒有事務,就新建一個事務。這是最多見的選擇。 code
SPT PROPAGATION_SUPPORTS-- 若是當前沒有事務,就以非事務方式執行。
MA: PROPAGATION_MANDATORY-- 若是當前沒有事務,就拋出異常。
RE_NEW: PROPAGATION_REQUIRES_NEW--新建事務,若是當前存在事務,把當前事務掛起。
NOT_SPT: PROPAGATION_NOT_SUPPORTED--以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。
NEVER: PROPAGATION_NEVER--以非事務方式執行,若是當前存在事務,則拋出異常。
經過上面發現,只有新建立資源的時候,纔會開啓事務,在其餘的狀況下,只須要返回事務狀態信息就能夠了。其實這個狀態信息,就是事務的上下文信息。
事務上下文
經過上面的分析,每次啓動事務的時候,都會判斷當前是否存在事務,要麼拋出異常,不然都會創新事務上下文,可是對於數據源的處理方式則是不同的,這個要根據當前事務傳播屬性和新的事務傳播屬性共同決定。
事務上下文信息究竟是什麼,這個徹底是能夠自定義的,在spring中,主要是表現爲TransactionStatus,也就是事務狀態信息。裏面保存了事務相關的信息,
//事務對象信息,使用普通數據源的話,是DataSourceTransactionObject對象,保存//了事務對應的鏈接信息 private final Object transaction; //是不是新開啓的事務信息,只有調用了開啓事務的方法,這個才爲true private final boolean newTransaction; //這個是事務同步器,不是事務要關心的,spring在事務提交以前或者以後座的hook private final boolean newSynchronization; //是不是隻讀事務 private final boolean readOnly; //日誌debug信息,徹底沒有放在這裏 private final boolean debug; //掛起的事務信息,若是沒有,則爲空 private final Object suspendedResources;
經過事務狀態信息,就能夠徹底知道當前事務的全部信息,包括事務的對應的數據源鏈接信息,是不是新建立的事務,是不是隻讀事務,以及以前掛起的事務信息。這些對事務管理器起來講,都是必須的信息。可是我的以爲也存在一些問題,首先spring這個事務狀態信息有兩個使用者,一個是spring自己事務管理器使用,另一個是應用程序接口。對應用程序接口暴露出來的狀態信息以及內部使用的事務上下文信息應該隔離出來,避免應用程序人爲的修改了事務上下文的屬性信息。固然,能夠用過接口的方式進行避免,可是若是知道實現原理的話,徹底能夠經過強制轉化爲實現對象,從而破壞事務其餘的信息致使程序異常。固然,正常狀況下不太可能有人會如此無聊。
從上面的分析來看,spring的事務管理器(這裏都特指DataSourceTransactionManager)主要的工做流程就是建立事務信息,綁定數據源,獲取數據庫鏈接,提交活回滾事務,釋放數據庫鏈接,解綁數據源。其實整個事務管理器作的事情無非就是這些。讓應用者更關注業務邏輯,而不是複雜的事務管理。
DataSourceTransactionManager事務管理器自己實現了ResouceManager的功能,就是返回對應的其註冊的datasrouce。這是一種一對一的映射關係,也就是說一個事務管理器只能註冊一個數據源,不支持多數據源的管理。一旦事務管理器開啓事務,就和具體的數據源綁定了,你只能經過其對應的數據源獲取數據庫鏈接。因此在事務上下文裏面操做多個數據庫,是不可能的。同時也只支持單一物理數據源,也就是說一個數據源只能返回同一個數據庫鏈接,不支持在同一個事務裏面經過同一個邏輯數據源跨越多個物理庫操做。下面的操做想經過ProxyDataSource切換實際的數據源的方式沒法實現的。
for(String dbName : dbNames){
DataSourceContextHolder.set(「dbName」);
doSomeThing();
DataSourceContextHolder.clear();
}
想要支持跨庫的事務操做,能夠經過如下幾種方式操做:
1 使用JtaTransactionManager,經過jta服務提供商來實現跨庫事務
2 改寫ProxyDataSource,經過返回其本身實現的Connection來實現跨庫的事務。簡單的說,返回一個邏輯的Connection,這個connection自己持有多個物理connection
3 本身實現TransactionManager,能夠註冊多個資源管理器,本身對多個數據源進行管理。
事務上下文的擴展
正常情經過況下,事務上下文信息都是保存在內存之中,至關於只可以支持單個jvm。能夠想象一下,假設事務管理器把事務上下文信息持久化,而且經過遠程調用的方式,把事務上下文信息傳遞給另一個jvm,經過這樣的設計思想,能夠支持跨jvm間的事務一致性,也就是咱們所說的分佈式系統的事務。固然,這只是一中簡單的想法,具體的實現會至關複雜,須要考慮點也有不少。