@Transactional 事務注解


@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class)
簡單解析:如果有事務,那么加入事務,沒有的話新建一個; 串行化最高級隔離級別; 遇到異常回滾。

 

 

@Transactional之value

    value這里主要用來指定不同的事務管理器;主要用來滿足在同一個系統中,存在不同的事務管理器。比如在Spring中,聲明了兩種事務管理器txManager1, txManager2.

然后,用戶可以根據這個參數來根據需要指定特定的txManager.

 

 

 

@Transactional之propagation(service中調用其他service時需要注意)

@Transactional(propagation=Propagation.REQUIRED) 如果有事務, 那么加入事務, 沒有的話新建一個(默認情況下)
@Transactional(propagation=Propagation.NOT_SUPPORTED)  容器不為這個方法開啟事務
@Transactional(propagation=Propagation.REQUIRES_NEW)  不管是否存在事務,都創建一個新的事務,原來的掛起,新的執行完畢,繼續執行老的事務
@Transactional(propagation=Propagation.MANDATORY)  必須在一個已有的事務中執行,否則拋出異常
@Transactional(propagation=Propagation.NEVER) 必須在一個沒有的事務中執行,否則拋出異常(與Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS)  如果其他bean調用這個方法,在其他bean中聲明事務,那就用事務。如果其他bean沒有聲明事務,那就

      Propagation支持7種不同的傳播機制:

  •  REQUIRED

               業務方法需要在一個事務中運行,如果方法運行時,已處在一個事務中,那么就加入該事務,否則自己創建一個新的事務.這是spring默認的傳播行為.。 

  •  SUPPORTS: 

               如果業務方法在某個事務范圍內被調用,則方法成為該事務的一部分,如果業務方法在事務范圍外被調用,則方法在沒有事務的環境下執行。

  •  MANDATORY:

               只能在一個已存在事務中執行,業務方法不能發起自己的事務,如果業務方法在沒有事務的環境下調用,就拋異常

  •  REQUIRES_NEW

             業務方法總是會為自己發起一個新的事務,如果方法已運行在一個事務中,則原有事務被掛起,新的事務被創建,直到方法結束,新事務才結束,原先的事務才會恢復執行.

  •  NOT_SUPPORTED

           聲明方法需要事務,如果方法沒有關聯到一個事務,容器不會為它開啟事務.如果方法在一個事務中被調用,該事務會被掛起,在方法調用結束后,原先的事務便會恢復執行.

  • NEVER:

              聲明方法絕對不能在事務范圍內執行,如果方法在某個事務范圍內執行,容器就拋異常.只有沒關聯到事務,才正常執行.

  •  NESTED:

          如果一個活動的事務存在,則運行在一個嵌套的事務中.如果沒有活動的事務,則按REQUIRED屬性執行.它使用了一個單獨的事務, 這個事務擁有多個可以回滾的保證點.內部事務回滾不會對外部事務造成影響, 它只對DataSourceTransactionManager 事務管理器起效.

     其實大家最感到困惑的是REQUIRED_NEW和NESTED兩種不同的傳播機制,功能類似,都涉及到了事務嵌套的問題,那兩者有何區別呢?該如何正確使用這兩種模式呢?

        以下是摘自Spring的文檔:
          PROPAGATION_REQUIRES_NEW : uses a completely independent transaction for each affected transaction scope. In that case, the underlying physical transactions are different and hence can commit or roll back independently, with an outer transaction not affected by an inner transaction's rollback status.
         內部的事務獨立運行,在各自的作用域中,可以獨立的回滾或者提交;而外部的事務將不受內部事務的回滾狀態影響。 
        ROPAGATION_NESTED : uses a single physical transaction with multiple savepoints that it can roll back to. Such partial rollbacks allow an inner transaction scope to trigger a rollback for its scope, with the outer transaction being able to continue the physical transaction despite some operations having been rolled back. This setting is typically mapped onto JDBC savepoints, so will only work with JDBC resource transactions.
       NESTED的事務,基於單一的事務來管理,提供了多個保存點。這種多個保存點的機制允許內部事務的變更觸發外部事務的回滾。而外部事務在混滾之后,仍能繼續進行事務處理,即使部分操作已經被混滾。 由於這個設置基於JDBC的保存點,所以只能工作在JDBC的機制智商。
       由此可知, 兩者都是事務嵌套,不同之處在於,內外事務之間是否存在彼此之間的影響;NESTED之間會受到影響,而產生部分回滾,而REQUIRED_NEW則是獨立的。
 
 
 
 
 @Transactional之isolation(多使用與多用戶並發操作數據庫,注意會引發的並發問題)
@Transactional(isolation = Isolation.READ_UNCOMMITTED) 讀取未提交數據(會出現臟讀, 不可重復讀) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED)(SQLSERVER默認) 讀取已提交數據(會出現不可重復讀和幻讀)
@Transactional(isolation = Isolation.REPEATABLE_READ) 可重復讀(會出現幻讀)
@Transactional(isolation = Isolation.SERIALIZABLE) 串行化

       隔離級別所要解決的問題是在應用程序中,存在多個事務同時在運行之時,需要解決和處理好的問題。那首先來看看,一般會出現哪些問題呢?先來看看吧。
  •       臟讀(dirty read)  
         一個事物更新了數據庫中的某些數據,另一個事物讀取了這些數據,這時前一個事物由於某些原因回滾了,那么第二個事物讀取的數據就是“臟數據” 
  •        不可重復讀(non-repeatable read)
        一個事物需要兩次查詢同一數據,但兩次查詢中間可能有另外一個事物更改了這個數據,導致前一個事物兩次讀出的數據不一致。
  •         幻讀 (phantom read)
           一個事物兩次查詢同一個表,但兩次查詢中間可能有另外一個事物又向這個表中插入了一些新數據,導致前一個事物的兩次查詢不一致  
  下面來看看Spring中@Transactional中Isolation有具備的值:
  •   DEFAULT  使用各個數據庫默認的隔離級別
  •   Read Uncommited :讀未提交數據( 會出現臟讀,不可重復讀,幻讀  )
  •  Read Commited :讀已提交的數據(會出現不可重復讀,幻讀)
  •  Repeatable Read :可重復讀(會出現幻讀)
  •  Serializable :串行化
具體如何來設置具體的隔離界別,則依據業務系統具體可以容忍的程度而定。Serializable最為嚴格,然而效率最低;Read Uncommited效率最高,但是容易出現各種問題,中間的2個級別介於二者之間,故本質上是效率與出錯概率的平衡與妥協。
 
 
 

@Transactional之timeout

      用於設置事務處理的時間長度,阻止可能出現的長時間的阻塞系統或者占用系統資源。單位為秒。如果超時設置事務回滾,並拋出TransactionTimedOutException異常。

    Spring事務超時 = 事務開始時到最后一個Statement創建時時間 + 最后一個Statement的執行時超時時間(即其queryTimeout)。

     關於事務超時時間的計算可以參考:http://jinnianshilongnian.iteye.com/blog/1986023

 

 

 

@Transactional之readOnly

      默認情況下是false,可以顯示指定為true, 告訴程序該方法下使用的是只讀操作,如果進行其他非讀操作,則會跑出異常;這個緊緊適用於只有readOnly標識的情況下,當其與propagation機制同時使用之時,則會出現只讀設置被覆蓋的情況,比如在required的情況下。在使用 REQUIRED 傳播模式時,會拋出一個只讀連接異常。使用 JDBC 時是這樣。使用基於 ORM 的框架時,只讀標志只是對數據庫的一個提示,並且一條基於 ORM 框架的指令(本例中是 hibernate)將對象緩存的 flush 模式設置為 NEVER,表示在這個工作單元中,該對象緩存不應與數據庫同步。不過,REQUIRED 傳播模式會覆蓋所有這些內容,允許事務啟動並工作,就好像沒有設置只讀標志一樣。

     具體的詳細內容可以參考: http://robinsoncrusoe.iteye.com/blog/825531

 

@Transactional之rollbackForClassName/rollbackFor

       Spring默認情況下會對運行期例外(RunTimeException)進行事務回滾。這個例外是unchecked,如果遇到checked意外就不回滾。

       用來指明回滾的條件是哪些異常類或者異常類名。用法比較簡單,這些不再贅述。

 

 

 

@Transactional之noRollbackForClassName/noRollbackFor
       作用雷同於8, 用來指明在拋出特定異常的情況下,不進行數據庫的事務回滾操作。

 

 

  • spring事務回滾規則
指示spring事務管理器回滾一個事務的推薦方法是在當前事務的上下文內拋出異常。spring事務管理器會捕捉任何未處理的異常,然后依據規則決定是否回滾拋出異常的事務。
默認配置下,spring只有在拋出的異常為運行時unchecked異常時才回滾該事務,也就是拋出的異常為RuntimeException的子類(Errors也會導致事務回滾),而拋出checked異常則不會導致事務回滾。
可以明確的配置在拋出那些異常時回滾事務,包括checked異常。也可以明確定義那些異常拋出時不回滾事務。
還可以編程性的通過setRollbackOnly()方法來指示一個事務必須回滾,在調用完setRollbackOnly()后你所能執行的唯一操作就是回滾。
 

 Spring @Transactional的注意事項
  • @Transactional 注解應該只被應用到 public 可見度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不會報錯, 但是這個被注解的方法將不會展示已配置的事務設置。
  • 用 spring 事務管理器,由spring來負責數據庫的打開,提交,回滾。默認遇到運行期異常(throw new RuntimeException("注釋");)會回滾,即遇到不受檢查(unchecked)的異常時回滾;而遇到需要捕獲的異常(throw new Exception("注釋");)不會回滾,即遇到受檢查的異常(就是非運行時拋出的異常,編譯器會檢查到的異常叫受檢查異常或說受檢查異常)時,需我們指定方式來讓事務回滾 要想所有異常都回滾,要加上 @Transactional( rollbackFor={Exception。class,其它異常}) 。
  • @Transactional 注解可以被應用於接口定義和接口方法、類定義和類的 public 方法上。然而,請注意僅僅 @Transactional 注解的出現不足於開啟事務行為,它僅僅是一種元數據,能夠被可以識別 @Transactional 注解和上述的配置適當的具有事務行為的beans所使用。上面的例子中,其實正是 <tx:annotation-driven/>元素的出現 開啟了事務行為。
  • Spring團隊的建議是你在具體的類(或類的方法)上使用 @Transactional 注解,而不要使用在類所要實現的任何接口上。你當然可以在接口上使用 @Transactional 注解,但是這將只能當你設置了基於接口的代理時它才生效。因為注解是不能繼承的,這就意味着如果你正在使用基於類的代理時,那么事務的設置將不能被基於類的代理所識別,而且對象也將不會被事務代理所包裝(將被確認為嚴重的)。因此,請接受Spring團隊的建議並且在具體的類上使用 @Transactional 注解。
  • @Transactional 注解標識的方法,處理過程盡量的簡單。尤其是帶鎖的事務方法,能不放在事務里面的最好不要放在事務里面。可以將常規的數據庫查詢操作放在事務前面進行,而事務內進行增、刪、改、加鎖查詢等操作。
  • @Transactional 的事務開啟 ,或者是基於接口的 或者是基於類的代理被創建。所以在同一個類中一個方法調用另一個方法有事務的方法,事務是不會起作用的。


免責聲明!

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



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