@Transactional 事務註解

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

 

 

@Transactional之valuejava

    value這裏主要用來指定不一樣的事務管理器;主要用來知足在同一個系統中,存在不一樣的事務管理器。好比在Spring中,聲明瞭兩種事務管理器txManager1, txManager2.spring

而後,用戶能夠根據這個參數來根據須要指定特定的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: 

               若是業務方法在某個事務範圍內被調用,則方法成爲該事務的一部分,若是業務方法在事務範圍外被調用,則方法在沒有事務的環境下執行。app

  •  MANDATORY:

               只能在一個已存在事務中執行,業務方法不能發起本身的事務,若是業務方法在沒有事務的環境下調用,就拋異常框架

  •  REQUIRES_NEW

             業務方法老是會爲本身發起一個新的事務,若是方法已運行在一個事務中,則原有事務被掛起,新的事務被建立,直到方法結束,新事務才結束,原先的事務纔會恢復執行.ui

  •  NOT_SUPPORTED

           聲明方法須要事務,若是方法沒有關聯到一個事務,容器不會爲它開啓事務.若是方法在一個事務中被調用,該事務會被掛起,在方法調用結束後,原先的事務便會恢復執行.spa

  • 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 的事務開啓 ,或者是基於接口的 或者是基於類的代理被建立。因此在同一個類中一個方法調用另外一個方法有事務的方法,事務是不會起做用的。
相關文章
相關標籤/搜索