Spring,為內部方法新起一個事務,此處應有坑。


  事務的作用,使我們操作能夠連貫起來。而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注解進行修飾。

 

  拼的就是工具的使用熟練度,哦。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM