在上兩篇 Spring Boot事務管理(上)和Spring Boot事務管理(中)的基礎上介紹注解@Transactional。
5 @Transactional屬性
屬性 |
類型 |
描述 |
value |
String |
指定使用的事務管理器 |
propagation |
enum: Propagation |
可選的事務傳播行為設置 |
isolation |
enum: Isolation |
可選的事務隔離級別設置 |
readOnly |
boolean |
讀寫或只讀事務,默認讀寫 |
timeout |
int,unit seconds |
事務超時時間設置 |
rollbackFor |
Class對象數組,必須繼承自Throwable |
導致事務回滾的異常類數組 |
rollbackForClassName |
類名數組,必須繼承自Throwable |
導致事務回滾的異常類名字數組 |
noRollbackFor |
Class對象數組,必須繼承自Throwable |
不會導致事務回滾的異常類數組 |
noRollbackForClassName |
類名數組,必須繼承自Throwable |
不會導致事務回滾的異常類名字數組 |
@Transactional 可以作用於接口、接口方法、類以及類方法上。當作用於類上時,該類的所有 public 方法將都具有該類型的事務屬性。同時,也可以在方法級別使用該注解來覆蓋類級別的注解。
Spring 建議不要在接口或者接口方法上使用該注解,因為這只有在使用基於接口的代理時它才會生效。另外, @Transactional 應該只被應用到 public 方法上,這是由 Spring AOP 的本質決定的。如果你在 protected、private 或者默認可見性的方法上使用它,這將被忽略,也不會拋出任何異常。
默認情況下,只有來自外部的方法調用才會被AOP代理捕獲,也就是,類內部方法調用本類內部的其他方法並不會引起事務行為,即使被調用方法使用@Transactional。
1 @Transactional(readOnly = true) 2 public class DefaultFooService implements FooService { 3 @Transactional
4 public Foo getFoo(String fooName) { 5 // do something
6 } 7
8 // these settings have precedence for this method
9 //方法上的注解屬性會覆蓋類注解上的相同屬性
10 @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) 11 public void updateFoo(Foo foo) { 12 // do something
13 } 14 }
如果getFoo在第5行調用updateFoo方法,則updateFoo無法觸發新的事務行為,因為該調用發生在目標Bean中,而不會通過代理Bean。為了解決這個問題,可以運行目標Bean在getFoo中訪問當前代理實例,並通過該代理實例執行updateFoo。此時,updateFoo的方法調用也會通過代理實例,並爭取完成事務划分。在調用updateFoo的時候,使用如下方式
((DefaultFooService)AopContext.currentProxy()).updateFoo(foo);
AopContext.currentProxy()靜態方法調用返回當前活動代理對象。在將其強制轉換為特點類型之后,就可以適當地調用updateFoo。然而,在默認情況下,Spring Framework並沒有公開代理,因為這么做產生一定的性能損失。如果需要此功能,可以在Spring Bean的配置文件中使用<aop:aspect-autoproxy expose-proxy=”true”/>元素來啟用該功能。
6 Reference
- https://www.cnblogs.com/kangoroo/p/8192503.html
- https://www.cnblogs.com/yepei/p/4716112.html
- https://blog.csdn.net/trigl/article/details/50968079
- Spring入門經典,北京:清華大學出版社,2015