事務的作用,使我們操作能夠連貫起來。而spring則是提供了一個更簡單的方法,只要使用 @Transactional 一個注解,就可以保證操作的連貫性了。
普通用法,稍后再說,這里要說的是: 在最外面的方法中,有一個@Transactional 的注解,當有拋出異常時,則進行回滾操作:
@Transactional(readOnly = false, rollbackFor = Throwable.class, isolation = Isolation.REPEATABLE_READ)
原本這個方法運行得好好的,但是有一天,我們需要在這個方法里添加一個新業務操作,而且這個業務操作是不要求回滾的,類似於做日志記錄一類的。WHAT SHOULD I DO ?
由於業務的獨特性,我能夠快速想到的是,在這個類里面加一個private方法,然后直接去調用就ok了,如果說還是考慮到回滾的話,我也快速想到 @Transactional 的NOT_SUPPORTED傳播特性,如:
@Transactional(propagation = Propagation.NOT_SUPPORTED) private void doMyExJob(UserDebitCardBean userDebitCard) { System.out.println("do my job..."); //do my job... }
這看起來很合理,沒毛病。
然而就是運行不起來,只要外面調用的方法一拋出異常,那么這個新方法的數據操作將會被回滾。媽蛋,到底哪里出了問題???仔細查了下資料,原來 @Transactional 注解由於原理決定了他只能作用於public方法中,而這里改為private,就完全被忽略無視了。OK,改唄:
@Transactional(propagation = Propagation.NOT_SUPPORTED) public void doMyExJob(UserDebitCardBean userDebitCard) { System.out.println("do my job..."); //do my job... }
感覺應該好了,然而並沒有。我也是醉了,這個問題,如果仔細花時間,找原理是沒有問題的,但是在關鍵時刻來這么一下,還是很不爽的。 網上看到一哥們說,還必須要將方法寫到另一個類中,而且要通過spring的注入方式進行調用,才可以。好吧,那我就按照他的來,結果真的成功了。
//在接口中進行了定義,能夠注入 @Override @Transactional(propagation = Propagation.NOT_SUPPORTED) public void doMyExJob(UserDebitCardBean userDebitCard) { System.out.println("do my job..."); //do my job... }
總算可以了,在趕時間的時候,能夠解決問題的,就是好方法。至此,問題解決。1. 使用public訪求;2. 寫在外部類中,可被調用; 3. 使用注入的方式進行該方法的執行。
說實話,spring這種事務還是有點不太好用的,要求太多,當然了,有很大部分原因是我沒有理解其精髓。OK,下面我們來看看spring事務的講解:
在配置文件中,默認情況下,<tx:annotation-driven>會自動使用名稱為transactionManager的事務管理器。所以,如果定義的事務管理器名稱為transactionManager,那么就可以直接使用<tx:annotation-driven/>。如下:
1
2
3
4
5
6
7
8
|
<!-- 配置事務管理器 -->
<
bean
id
=
"transactionManager"
class
=
"org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref
=
"dataSource"
>
</
bean
>
<!-- enables scanning for @Transactional annotations -->
<
tx:annotation-driven
/>
|
<tx:annotation-driven>一共有四個屬性如下,
- mode:指定Spring事務管理框架創建通知bean的方式。可用的值有proxy和aspectj。前者是默認值,表示通知對象是個JDK代理;后者表示Spring AOP會使用AspectJ創建代理
- proxy-target-class:如果為true,Spring將創建子類來代理業務類;如果為false,則使用基於接口的代理。(如果使用子類代理,需要在類路徑中添加CGLib.jar類庫)
- order:如果業務類除事務切面外,還需要織入其他的切面,通過該屬性可以控制事務切面在目標連接點的織入順序。
- transaction-manager:指定到現有的PlatformTransaction Manager bean的引用,通知會使用該引用
@Transactional的屬性
isolation 枚舉org.springframework.transaction.annotation.Isolation的值 事務隔離級別
noRollbackFor Class<? extends Throwable>[] 一組異常類,遇到時不回滾。默認為{}
noRollbackForClassName Stirng[] 一組異常類名,遇到時不回滾,默認為{}
propagation 枚舉org.springframework.transaction.annotation.Propagation的值 事務傳播行為
readOnly boolean 事務讀寫性
rollbackFor Class<? extends Throwable>[] 一組異常類,遇到時回滾
rollbackForClassName Stirng[] 一組異常類名,遇到時回滾
timeout int 超時時間,以秒為單位
value String 可選的限定描述符,指定使用的事務管理器
@Transactional標注的位置
@Transactional注解可以標注在類和方法上,也可以標注在定義的接口和接口方法上。
如果我們在接口上標注@Transactional注解,會留下這樣的隱患:因為注解不能被繼承,所以業務接口中標注的@Transactional注解不會被業務實現類繼承。所以可能會出現不啟動事務的情況。所以,spring建議我們將@Transaction注解在實現類上。
在方法上的@Transactional注解會覆蓋掉類上的@Transactional。
注意:
@Transactional 可以作用於接口、接口方法、類以及類方法上。當作用於類上時,該類的所有 public 方法將都具有該類型的事務屬性,同時,我們也可以在方法級別使用該標注來覆蓋類級別的定義。
雖然 @Transactional 注解可以作用於接口、接口方法、類以及類方法上,但是 Spring 建議不要在接口或者接口方法上使用該注解,因為這只有在使用基於接口的代理時它才會生效。另外, @Transactional 注解應該只被應用到 public 方法上,這是由 Spring AOP 的本質決定的。如果你在 protected、private 或者默認可見性的方法上使用 @Transactional 注解,這將被忽略,也不會拋出任何異常。
默認情況下,只有來自外部的方法調用才會被AOP代理捕獲,也就是,類內部方法調用本類內部的其他方法並不會引起事務行為,即使被調用方法使用@Transactional注解進行修飾。
拼的就是工具的使用熟練度,哦。