前言:有時(shí)候在編寫代碼過程中甸鸟,遇到事物不生效的問題惦费,特此總結(jié)一下
代碼如下
public class DemoTransactional {
public void demoTestA() {
// sql執(zhí)行邏輯 。抢韭。薪贫。
demoTestB();
}
@Transactional
public void demoTestB() {
// sql執(zhí)行邏輯 。刻恭。瞧省。
}
}
測(cè)試結(jié)果如下:
- 經(jīng)過測(cè)試發(fā)現(xiàn),當(dāng)
demoTestA
方法調(diào)用同類中帶有@Transactional
注解的demoTestB
方法時(shí)鳍贾,被@Transactional
注解的demoTestB方法
的事務(wù)是不起作用的
原因如下:
Spring采用動(dòng)態(tài)代理(AOP)實(shí)現(xiàn)對(duì)bean的管理和切片鞍匾,它為我們的每個(gè)class生成一個(gè)代理對(duì)象。只有在代理對(duì)象之間進(jìn)行調(diào)用時(shí)骑科,可以觸發(fā)切面邏輯橡淑。
而在同一個(gè)class中,demoTestA
調(diào)用方法demoTestB
咆爽,調(diào)用的是原對(duì)象的方法梁棠,而不通過代理對(duì)象。所以Spring無法切到這次調(diào)用斗埂,也就無法通過注解保證事務(wù)性了符糊。
也就是說,在同一個(gè)類中的方法調(diào)用呛凶,則不會(huì)被方法攔截器攔截到男娄,因此事務(wù)不會(huì)起作用。
另一種理解
Spring在處理@Tranasctional注解時(shí)漾稀,會(huì)“proxy”當(dāng)前的類模闲。如果A和B兩個(gè)類都有@Transactional時(shí),實(shí)際上運(yùn)行的是A的代理類A‘, A县好,B的代理類B'围橡, B四個(gè)類的instance。一個(gè)外部服務(wù)調(diào)用A缕贡,實(shí)際上是 外部-->A'-->A-->B'-->B這樣執(zhí)行的翁授。而拋出異常的代碼實(shí)際上是在B‘做的拣播。但是如果是同一個(gè)類內(nèi)部方法直接調(diào)用的話,那么就是簡(jiǎn)單的方法直接調(diào)用收擦,即 外部-->A'-->A方法1-->A方法2贮配。 A方法1不會(huì)找到A'去調(diào)用。于是塞赂,“傳播”的規(guī)則不會(huì)生效泪勒。
解決方法
- 將帶有@Transactional注解的方法移到另一個(gè)類中,發(fā)起類之間的方法調(diào)用宴猾。
- 在第一個(gè)方法中也添加@Transactional注解圆存。
經(jīng)過測(cè)試的情況總結(jié)
前提:demoTestA
方法調(diào)用demoTestB
方法時(shí),demoTestB
方法有多個(gè)修改SQL
測(cè)試結(jié)果
-
demoTestA
方法沒開啟事務(wù)仇哆,demoTestB
方法開啟事務(wù):demoTestA
和demoTestB
在同一類中沦辙,事務(wù)無效;demoTestA
和demoTestB
不在同一類中讹剔,事務(wù)生效油讯。 -
demoTestA
方法開啟事務(wù),demoTestB
方法沒開啟事務(wù):demoTestA
和demoTestB
在同一類中延欠,事務(wù)生效陌兑;demoTestA
和demoTestB
不在同一類中,事務(wù)生效由捎。