1.REQUIRED
REQUIRED(Spring默認(rèn)的事務(wù)傳播類型 required):如果當(dāng)前沒有事務(wù),則自己新建一個事務(wù)偷遗,如果當(dāng)前存在事務(wù)則加入這個事務(wù)驶忌。
當(dāng)A調(diào)用B的時候:如果A中沒有事務(wù),B中有事務(wù)粥航,那么B會新建一個事務(wù);如果A中也有事務(wù)生百、B中也有事務(wù)递雀,那么B會加入到A中去,變成一個事務(wù)蚀浆,這時缀程,要么都成功,要么都失敗蜡坊。
class ServiceA {
@Autowired
ServiceB serviceB杠输;
@Transactional
void a() {
....
serviceB.b();
....
}
}
class ServiceB {
@Transactional
void b() {
......
}
}
- 線程執(zhí)行到serviceA.a() 方法時,其實(shí)是執(zhí)行的 代理serviceA對象的a方法秕衙。
- 執(zhí)行代理serviceA對象的a方法
2.1: 執(zhí)行a方法的增強(qiáng)邏輯-> 事務(wù)增強(qiáng)器 (環(huán)繞增強(qiáng))
2.2: 事務(wù)增強(qiáng)器會做什么事? 提取事務(wù)標(biāo)簽屬性
2.3: 檢查當(dāng)前線程有沒有綁定 conn 數(shù)據(jù)庫連接 資源蠢甲? 發(fā)現(xiàn)當(dāng)前線程未綁定(TransactionSync...Manager#resources 是 ThreadLocal<Map<obj,obj>>,檢查key:datasource 有沒有數(shù)據(jù))
2.4: 因?yàn)槲唇壎╟onn資源据忘,所以線程下一步就是 到 datasource.getConnection() 獲取一個conn資源
2.5: 因?yàn)樾芦@取的conn資源的autocommit是true鹦牛,所以這一步 修改 autocommit 為false,表示手動提交事務(wù)勇吊,這一步也表示 開啟事務(wù)(修改conn其它 屬性..)
2.6: 綁定conn資源到 TransactionSync...Manager#resources曼追,key:datasource - 執(zhí)行事務(wù)增強(qiáng)器后面的增強(qiáng)器..
- 最后一個advice調(diào)用 target的目標(biāo)方法 a() 方法
4.1: 假設(shè)target a方法 需要訪問數(shù)據(jù)庫 執(zhí)行SQL 的話,程序需要獲取一個 conn 資源汉规,到哪拿礼殊? DataSourceUtils.getConnection(datasource) 這一步最終會拿到 事務(wù)增強(qiáng)器 前置增強(qiáng)邏輯 存放在 TransactionSync..Manager#resources 內(nèi)的
conn 資源
4.2: 執(zhí)行方法a邏輯...可能會執(zhí)行一些 SQL 語句... - 線程執(zhí)行到這樣一行代碼:serviceB.b()
- serviceB 它是一個代理對象驹吮,因?yàn)樗彩褂昧?@Transactional 注解了,Spring 會為它創(chuàng)建代理的晶伦。
- 執(zhí)行代理serviceB對象的b方法
7.1: 執(zhí)行b方法的增強(qiáng)邏輯-> 事務(wù)增強(qiáng)器(環(huán)繞增強(qiáng))
7.2: 事務(wù)增強(qiáng)器會做什么事? 提取事務(wù)標(biāo)簽屬性
7.3: 檢查當(dāng)前線程有沒有綁定 conn 數(shù)據(jù)庫連接 資源碟狞?發(fā)現(xiàn)當(dāng)前線程已經(jīng)綁定了 conn 數(shù)據(jù)庫連接資源了
7.4: 檢查事務(wù)注解屬性,發(fā)現(xiàn)自己打的propagation == REQUIRED婚陪,所以繼續(xù)共享 conn 數(shù)據(jù)庫鏈接資源 - 執(zhí)行事務(wù)增強(qiáng)器后面的增強(qiáng)器..
- 最后一個device調(diào)用 target (serviceB)的目標(biāo)方法 b() 方法
9.1: 假設(shè)target b方法 需要訪問數(shù)據(jù)庫 執(zhí)行SQL 的話族沃,程序需要獲取一個 conn 資源,到哪拿泌参? DataSourceUtils.getConnection(datasource) 這一步最終會拿到 代理serviceA對象存放在 TransactionSync..Manager#resources 內(nèi)的
conn 資源
9.2: 執(zhí)行方法b邏輯...可能會執(zhí)行一些 SQL 語句... - 線程繼續(xù)執(zhí)行 事務(wù)增強(qiáng)器 環(huán)繞增強(qiáng)的后置邏輯 (代理serviceB.b() 方法的 后置增強(qiáng))
10.1: 檢查發(fā)現(xiàn)脆淹,serviceB.b() 事務(wù)并不是 當(dāng)前 b方法開啟的,所以 基本不做什么事情.. - 線程繼續(xù)回到 目標(biāo) serviceA.a() 方法內(nèi)沽一,繼續(xù)執(zhí)行
11.1: 執(zhí)行方法a邏輯...可能會執(zhí)行一些 SQL 語句... - 線程繼續(xù)回到 代理 serviceA.a() 方法內(nèi)盖溺,繼續(xù)執(zhí)行
12.1: 執(zhí)行a方法的增強(qiáng)邏輯-> 事務(wù)增強(qiáng)器 (環(huán)繞增強(qiáng)-后置增強(qiáng)邏輯)
12.2: 提交事務(wù)/回滾事務(wù)
12.3: 恢復(fù)連接狀態(tài) (將conn的autocommit 設(shè)置回 true...等等)
12.4: 清理工作(將綁定的conn資源從TransactionSync...Manager#resources移除)
12.5: conn 連接關(guān)閉 (歸還連接到datasource)
2.SUPPORTS
SUPPORTS:當(dāng)前存在事務(wù),則加入當(dāng)前事務(wù)锯玛,如果當(dāng)前沒有事務(wù)咐柜,就以非事務(wù)方法執(zhí)行兼蜈。
如果A中有事務(wù)攘残,則B方法的事務(wù)加入A事務(wù)中,成為一個事務(wù)(一起成功为狸,一起失敿吖),如果A中沒有事務(wù)辐棒,那么B就以非事務(wù)方式運(yùn)行(執(zhí)行完直接提交)病曾。
class ServiceA {
@Autowired
ServiceB serviceB;
@Transactional
void a() {
....
serviceB.b();
....
}
}
class ServiceB {
@Transactional(propagation = SUPPORTS)
void b() {
......
}
}
邏輯和上面 完全一致漾根。
class ServiceA {
@Transactional(Propagation = SUPPORTS)
void a() {
....
....
}
}
線程在未綁定事務(wù)的情況下泰涂,去調(diào)用serviceA.a() 方法會發(fā)生什么呢?
- 線程執(zhí)行到serviceA.a() 方法時辐怕,其實(shí)是執(zhí)行的 代理serviceA對象的a方法逼蒙。
- 執(zhí)行代理serviceA對象的a方法
2.1: 執(zhí)行a方法的增強(qiáng)邏輯-> 事務(wù)增強(qiáng)器 (環(huán)繞增強(qiáng))
2.2: 事務(wù)增強(qiáng)器會做什么事? 提取事務(wù)標(biāo)簽屬性
2.3: 檢查當(dāng)前線程有沒有綁定 conn 數(shù)據(jù)庫連接 資源? 發(fā)現(xiàn)當(dāng)前線程未綁定(TransactionSync...Manager#resources 是 ThreadLocal<Map<obj,obj>>寄疏,檢查key:datasource 有沒有數(shù)據(jù))
2.4: 啥也不用做.. - 執(zhí)行事務(wù)增強(qiáng)器后面的增強(qiáng)器..
- 最后一個advice調(diào)用 target的目標(biāo)方法 a() 方法
4.1: 假設(shè)target a方法 需要訪問數(shù)據(jù)庫 執(zhí)行SQL 的話是牢,程序需要獲取一個 conn 資源陕截,到哪拿? DataSourceUtils.getConnection(datasource) 农曲,因?yàn)槭聞?wù)增強(qiáng)器前置增強(qiáng)邏輯 并沒有 向TransactionSync..Manager#resources 內(nèi)綁定conn資源
4.2: 因?yàn)?上一步未拿到 conn資源,所以 DataSourceUtils 通過 datasource.getConnection() 獲取了一個全新的 conn 資源(注意:conn.autocommit == true,執(zhí)行的每一條sql 都是一個 獨(dú)立事務(wù)!H春骸)
4.3: 執(zhí)行方法a邏輯...可能會執(zhí)行一些 SQL 語句... - 線程繼續(xù)執(zhí)行到代理serviceA對象的a方法 (事務(wù)增強(qiáng)器-后置增強(qiáng)邏輯)
5.1: 檢查發(fā)現(xiàn) TrasactionSync..Manager#resources 并未綁定任何 conn 資源,所以 這一步啥也不做了...
3.MANDATORY
MANDATORY(mandatory:強(qiáng)制性的):當(dāng)前存在事務(wù)合砂,則加入當(dāng)前事務(wù),如果當(dāng)前事務(wù)不存在源织,則拋出異常。
如果A中有事務(wù)谈息,則B方法的事務(wù)加入A事務(wù)中,成為一個事務(wù)(一起成功侠仇,一起失敗)逻炊;如果A中沒有事務(wù),B中有事務(wù)余素,那么B就直接拋異常了,意思是B必須要支持回滾的事務(wù)中運(yùn)行桨吊。
class ServiceA {
@Autowired
ServiceB serviceB威根;
@Transactional
void a() {
....
serviceB.b();
....
}
}
class ServiceB {
@Transactional(propagation = MANDATORY)
void b() {
......
}
}
如果是這樣的話,情況和 PROPAGATION_REQUIRED 案例分析 完全一致视乐。
class ServiceA {
@Transactional(Propagation = MANDATORY)
void a() {
....
....
}
}
線程在未綁定事務(wù)的情況下洛搀,去調(diào)用serviceA.a() 方法會發(fā)生什么呢?
- 線程執(zhí)行到serviceA.a() 方法時佑淀,其實(shí)是執(zhí)行的 代理serviceA對象的a方法留美。
- 執(zhí)行代理serviceA對象的a方法
2.1: 執(zhí)行a方法的增強(qiáng)邏輯-> 事務(wù)增強(qiáng)器 (環(huán)繞增強(qiáng))
2.2: 事務(wù)增強(qiáng)器會做什么事? 提取事務(wù)標(biāo)簽屬性
2.3: 檢查當(dāng)前線程有沒有綁定 conn 數(shù)據(jù)庫連接 資源? 發(fā)現(xiàn)當(dāng)前線程未綁定(TransactionSync...Manager#resources 是 ThreadLocal<Map<obj,obj>>渣聚,檢查key:datasource 有沒有數(shù)據(jù))
2.4: 直接拋出異常...
4.REQUIRES_NEW
REQUIRES_NEW:創(chuàng)建一個新事務(wù)独榴,如果存在當(dāng)前事務(wù),則掛起該事務(wù)奕枝。
B會新建一個事務(wù)棺榔,A和B事務(wù)互不干擾,他們出現(xiàn)問題回滾的時候隘道,也都只回滾自己的事務(wù)症歇;A方法調(diào)用B方法郎笆;不管A方法有沒有事務(wù),B方法都新建一個自己的事務(wù)忘晤。
class ServiceA {
@Autowired
ServiceB serviceB宛蚓;
@Transactional
void a() {
....
serviceB.b();
....
}
}
class ServiceB {
@Transactional(propagation = REQUIRES_NEW)
void b() {
......
}
}
線程執(zhí)行到serviceA.a() 方法時,其實(shí)是執(zhí)行的 代理serviceA對象的a方法设塔。
執(zhí)行代理serviceA對象的a方法
2.1: 執(zhí)行a方法的增強(qiáng)邏輯-> 事務(wù)增強(qiáng)器 (環(huán)繞增強(qiáng))
2.2: 事務(wù)增強(qiáng)器會做什么事? 提取事務(wù)標(biāo)簽屬性
2.3: 檢查當(dāng)前線程有沒有綁定 conn 數(shù)據(jù)庫連接 資源凄吏? 發(fā)現(xiàn)當(dāng)前線程未綁定(TransactionSync...Manager#resources 是 ThreadLocal<Map<obj,obj>>,檢查key:datasource 有沒有數(shù)據(jù))
2.4: 因?yàn)槲唇壎╟onn資源闰蛔,所以線程下一步就是 到 datasource.getConnection() 獲取一個conn資源
2.5: 因?yàn)樾芦@取的conn資源的autocommit是true痕钢,所以這一步 修改 autocommit 為false,表示手動提交事務(wù)序六,這一步也表示 開啟事務(wù)(修改conn其它 屬性..)
2.6: 綁定conn資源到 TransactionSync...Manager#resources任连,key:datasource執(zhí)行事務(wù)增強(qiáng)器后面的增強(qiáng)器..
最后一個advice調(diào)用 target的目標(biāo)方法 a() 方法
4.1: 假設(shè)target a方法 需要訪問數(shù)據(jù)庫 執(zhí)行SQL 的話,程序需要獲取一個 conn 資源例诀,到哪拿随抠? DataSourceUtils.getConnection(datasource) 這一步最終會拿到 事務(wù)增強(qiáng)器 前置增強(qiáng)邏輯 存放在 TransactionSync..Manager#resources 內(nèi)的
conn 資源
4.2: 執(zhí)行方法a邏輯...可能會執(zhí)行一些 SQL 語句...線程執(zhí)行到這樣一行代碼:serviceB.b()
serviceB 它是一個代理對象,因?yàn)樗彩褂昧?@Transactional 注解了繁涂,Spring 會為它創(chuàng)建代理的拱她。
執(zhí)行代理serviceB對象的b方法
7.1: 執(zhí)行b方法的增強(qiáng)邏輯-> 事務(wù)增強(qiáng)器(環(huán)繞增強(qiáng))
7.2: 事務(wù)增強(qiáng)器會做什么事? 提取事務(wù)標(biāo)簽屬性
7.3: 檢查發(fā)現(xiàn)當(dāng)前線程已經(jīng)綁定了conn資源(并且手動開啟了事務(wù)..),又發(fā)現(xiàn) 當(dāng)前方法的 傳播行為:REQUIRES_NEW 爆土,需要開啟一個新的事務(wù)..
7.4: 將已經(jīng)綁定的conn資源 保存到 suspand 變量內(nèi)
7.5: 因?yàn)?REQUIRES_NEW 不會和上層共享同一個事務(wù)椭懊,所以這一步 又到 datasource.getConnection() 獲取了一個全新的 conn 數(shù)據(jù)庫連接資源
7.6: 因?yàn)樾芦@取的conn資源的autocommit是true,所以這一步 修改 autocommit 為false,表示手動提交事務(wù)背犯,這一步也表示 開啟事務(wù)(修改conn其它 屬性..)
7.7: 綁定conn資源到 TransactionSync...Manager#resources,key:datasource執(zhí)行事務(wù)增強(qiáng)器后面的增強(qiáng)器..
最后一個advice調(diào)用 target (serviceB)的目標(biāo)方法 b() 方法
9.1: 假設(shè)target b方法 需要訪問數(shù)據(jù)庫 執(zhí)行SQL 的話倔矾,程序需要獲取一個 conn 資源柱锹,到哪拿? DataSourceUtils.getConnection(datasource) 這一步最終會拿到 事務(wù)增強(qiáng)器 前置增強(qiáng)邏輯 存放在 TransactionSync..Manager#resources 內(nèi)的
conn 資源
9.2: 執(zhí)行方法a邏輯...可能會執(zhí)行一些 SQL 語句...線程繼續(xù)執(zhí)行 事務(wù)增強(qiáng)器 環(huán)繞增強(qiáng)的后置邏輯 (代理serviceB.b() 方法的 后置增強(qiáng))
10.1: 檢查發(fā)現(xiàn)壤巷,serviceB.b() 事務(wù)是 b方法開啟的瞧毙,所以 需要做一些事情了
10.1: 執(zhí)行b方法的增強(qiáng)邏輯-> 事務(wù)增強(qiáng)器 (環(huán)繞增強(qiáng)-后置增強(qiáng)邏輯)
10.2: 提交事務(wù)/回滾事務(wù)
10.3: 恢復(fù)連接狀態(tài) (將conn的autocommit 設(shè)置回 true...等等)
10.4: 清理工作(將綁定的conn資源從TransactionSync...Manager#resources移除)
10.5: conn 連接關(guān)閉 (歸還連接到datasource)
10.6: 檢查suspand 發(fā)現(xiàn) 該變量有值,需要執(zhí)行 恢復(fù)現(xiàn)場的工作 resume()恢復(fù)現(xiàn)場
11.1: 將suspand 掛起的 conn 資源再次 綁定到 TransactionSync...Manager#resources 內(nèi)矩动,方便 serviceA 繼續(xù)使用它的conn資源 (它自己的事務(wù))線程繼續(xù)回到 serviceA.a() 方法內(nèi)
12.1: 繼續(xù)執(zhí)行一些sql ...注意 這里它使用的 conn 是 serviceA 申請的 conn線程繼續(xù)執(zhí)行 事務(wù)增強(qiáng)器 環(huán)繞增強(qiáng)的后置邏輯 (代理serviceA.a() 方法的 后置增強(qiáng))
10.1: 檢查發(fā)現(xiàn)悲没,serviceA.a() 事務(wù)是 a方法開啟的,所以 需要做一些事情了
10.1: 執(zhí)行a方法的增強(qiáng)邏輯-> 事務(wù)增強(qiáng)器 (環(huán)繞增強(qiáng)-后置增強(qiáng)邏輯)
10.2: 提交事務(wù)/回滾事務(wù)
10.3: 恢復(fù)連接狀態(tài) (將conn的autocommit 設(shè)置回 true...等等)
10.4: 清理工作(將綁定的conn資源從TransactionSync...Manager#resources移除)
10.5: conn 連接關(guān)閉 (歸還連接到datasource)
5.NOT_SUPPORTED
NOT_SUPPORTED: 以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù)柑潦,則掛起當(dāng)前事務(wù)
被調(diào)用者B會以非事務(wù)方式運(yùn)行(直接提交)峻凫,如果當(dāng)前有事務(wù),也就是A中有事務(wù)譬胎,A會被掛起(不執(zhí)行堰乔,等待B執(zhí)行完脐恩,返回);A和B出現(xiàn)異常需要回滾苟翻,互不影響
6.NEVER
NEVER: 如果當(dāng)前沒有事務(wù)存在骗污,就以非事務(wù)方式執(zhí)行需忿;如果有,就拋出異常涕烧。就是B從不以事務(wù)方式運(yùn)行
A中不能有事務(wù)汗洒,如果沒有,B就以非事務(wù)方式執(zhí)行痹扇,如果A存在事務(wù),那么直接拋異常
7.NESTED
NESTED: 嵌套事務(wù):如果當(dāng)前事務(wù)存在浓恶,則在嵌套事務(wù)中執(zhí)行结笨,否則REQUIRED的操作一樣(開啟一個事務(wù))
如果A中沒有事務(wù),那么B創(chuàng)建一個事務(wù)執(zhí)行伐憾,如果A中也有事務(wù)树肃,那么B會會把事務(wù)嵌套在里面瀑罗。