您好,登錄后才能下訂單哦!
這篇文章主要講解了“如何掌握Spring事務管理+事物隔離級別”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何掌握Spring事務管理+事物隔離級別”吧!
事務是邏輯上的一組操作。組成這組操作的各個邏輯單元必須全部完成,如果有一個失敗的話,那么事務就會回滾到最開始的狀態,仿佛什么都沒發生過一樣。
原子性(Atomicity):事務是一個原子操作,由一系列動作組成。事務的原子性確保動作要么全部完成,要么完全不起作用。
一致性(Consistency):一旦事務完成(不管成功還是失敗),系統必須確保它所建模的業務處于一致的狀態,而不會是部分完成部分失敗。在現實中的數據不應該被破壞。
隔離性(Isolation):可能有許多事務會同時處理相同的數據,因此每個事務都應該與其他事務隔離開來,防止數據損壞。
持久性(Durability):一旦事務完成,無論發生什么系統錯誤,它的結果都不應該受到影響,這樣就能從任何系統崩潰中恢復過來。通常情況下,事務的結果被寫到持久化存儲器中。
事務的第一個方面是傳播行為(propagation behavior)。當事務方法被另一個事務方法調用時,必須指定事務應該如何傳播。例如:方法可能繼續在現有事務中運行,也可能開啟一個新事務,并在自己的事務中運行。Spring定義了七種傳播行為:
傳播行為 | 含義 |
---|---|
PROPAGATION_REQUIRED | 表示當前方法必須運行在事務中。如果當前事務存在,方法將會在該事務中運行。否則,會啟動一個新的事務 |
PROPAGATION_SUPPORTS | 表示當前方法不需要事務上下文,但是如果存在當前事務的話,那么該方法會在這個事務中運行 |
PROPAGATION_MANDATORY | 表示該方法必須在事務中運行,如果當前事務不存在,則會拋出一個異常 |
PROPAGATION_REQUIRED_NEW | 表示當前方法必須運行在它自己的事務中。一個新的事務將被啟動。如果存在當前事務,在該方法執行期間,當前事務會被掛起。如果使用JTATransactionManager的話,則需要訪問TransactionManager |
PROPAGATION_NOT_SUPPORTED | 表示該方法不應該運行在事務中。如果存在當前事務,在該方法運行期間,當前事務將被掛起。如果使用JTATransactionManager的話,則需要訪問TransactionManager |
PROPAGATION_NEVER | 表示當前方法不應該運行在事務上下文中。如果當前正有一個事務在運行,則會拋出異常 |
PROPAGATION_NESTED | 表示如果當前已經存在一個事務,那么該方法將會在嵌套事務中運行。嵌套的事務可以獨立于當前事務進行單獨地提交或回滾。如果當前事務不存在,那么其行為與PROPAGATION_REQUIRED一樣。注意各廠商對這種傳播行為的支持是有所差異的。可以參考資源管理器的文檔來確認它們是否支持嵌套事務 |
(下面是通俗講解) | |
當事務方法被另一個事務方法調用時,必須指定事務應該如何傳播。例如:方法可能繼續在現有事務中運行,也可能開啟一個新事務,并在自己的事務中運行。Spring定義了七種傳播行為: |
1》PROPAGATION_REQUIRED 如果存在一個事務,則支持當前事務。如果沒有事務則開啟一個新的事務。
2》PROPAGATION_SUPPORTS 如果存在一個事務,支持當前事務。如果沒有事務,則非事務的執行。但是對于事務同步的事務管理器,PROPAGATION_SUPPORTS與不使用事務有少許不同。
3》PROPAGATION_MANDATORY 如果已經存在一個事務,支持當前事務。如果沒有一個活動的事務,則拋出異常。
4》PROPAGATION_REQUIRES_NEW 總是開啟一個新的事務。如果一個事務已經存在,則將這個存在的事務掛起。
我把ts1稱為外層事務,ts2稱為內層事務。從上面的代碼可以看出,ts2與ts1是兩個獨立的事務,互不相干。Ts2是否成功并不依賴于 ts1。如果methodA方法在調用methodB方法后的doSomeThingB方法失敗了,而methodB方法所做的結果依然被提交。而除了 methodB之外的其它代碼導致的結果卻被回滾了。使用PROPAGATION_REQUIRES_NEW,需要使用JtaTransactionManager作為事務管理器。
5》PROPAGATION_NOT_SUPPORTED 總是非事務地執行,并掛起任何存在的事務。使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作為事務管理器。
6》PROPAGATION_NEVER 總是非事務地執行。表示當前方法不應該運行在事務上下文中。如果當前正有一個事務在運行,則會拋出異常。(當事務方法被另一個事務方法調用時)如果存在一個活動事務,則拋出異常。
7》PROPAGATION_NESTED如果一個活動的事務存在,則運行在一個嵌套的事務中. 如果沒有活動事務, 則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執行。
這是一個嵌套事務,使用JDBC 3.0驅動時,僅僅支持DataSourceTransactionManager作為事務管理器。需要JDBC 驅動的java.sql.Savepoint類。
有一些JTA的事務管理器實現可能也提供了同樣的功能。使用PROPAGATION_NESTED,還需要把PlatformTransactionManager的nestedTransactionAllowed屬性設為true;而 nestedTransactionAllowed屬性值默認為false。
嵌套事務一個非常重要的概念就是內層事務依賴于外層事務。外層事務失敗時,會回滾內層事務所做的動作。而內層事務操作失敗并不會引起外層事務的回滾。
1》PROPAGATION_NESTED 與PROPAGATION_REQUIRES_NEW的區別:它們非常類似,都像一個嵌套事務,如果不存在一個活動的事務,都會開啟一個新的事務。使用 PROPAGATION_REQUIRES_NEW時,內層事務與外層事務就像兩個獨立的事務一樣,一旦內層事務進行了提交后,外層事務不能對其進行回滾。兩個事務互不影響。兩個事務不是一個真正的嵌套事務。同時它需要JTA事務管理器的支持。
2》使用PROPAGATION_NESTED時,外層事務的回滾可以引起內層事務的回滾。而內層事務的異常并不會導致外層事務的回滾,它是一個真正的嵌套事務。DataSourceTransactionManager使用savepoint支持PROPAGATION_NESTED時,需要JDBC 3.0以上驅動及1.4以上的JDK版本支持。其它的JTA TrasactionManager實現可能有不同的支持方式。
3》PROPAGATION_REQUIRES_NEW 啟動一個新的, 不依賴于環境的 “內部” 事務. 這個事務將被完全 commited 或 rolled back 而不依賴于外部事務, 它擁有自己的隔離范圍, 自己的鎖, 等等. 當內部事務開始執行時, 外部事務將被掛起, 內務事務結束時, 外部事務將繼續執行。
4》另一方面, PROPAGATION_NESTED 開始一個 “嵌套的” 事務, 它是已經存在事務的一個真正的子事務. 潛套事務開始執行時, 它將取得一個 savepoint. 如果這個嵌套事務失敗, 我們將回滾到此 savepoint. 潛套事務是外部事務的一部分, 只有外部事務結束后它才會被提交。
5》由此可見, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大區別在于, PROPAGATION_REQUIRES_NEW 完全是一個新的事務, 而 PROPAGATION_NESTED 則是外部事務的子事務, 如果外部事務 commit, 嵌套事務也會被 commit, 這個規則同樣適用于 roll back.
6》PROPAGATION_REQUIRED應該是我們首先的事務傳播行為。它能夠滿足我們大多數的事務需求。
事務的第二個維度就是隔離級別(isolation level)。隔離級別定義了一個事務可能受其他并發事務 影響的程度。
在典型的應用程序中,多個事務并發運行,經常會操作相同的數據來完成各自的任務。并發雖然是必須的,但可能會導致以下的問題:
臟讀(Dirty reads)——臟讀發生在一個事務讀取了另一個事務改寫但尚未提交的數據時。如果改寫在稍后被回滾了,那么第一個事務獲取的數據就是無效的。
不可重復讀(Nonrepeatable read)——不可重復讀發生在一個事務執行相同的查詢兩次或兩次以上,但是每次都得到不同的數據時。這通常是因為另一個并發事務在兩次查詢期間進行了更新。
幻讀(Phantom read)——幻讀與不可重復讀類似。它發生在一個事務(T1)讀取了幾行數據,接著另一個并發事務(T2)插入了一些數據時。在隨后的查詢中,第一個事務(T1)就會發現多了一些原本不存在的記錄。
不可重復讀的重點是修改:同樣的條件, 你讀取過的數據, 再次讀取出來發現值不一樣了
幻讀的重點在于新增或者刪除:同樣的條件, 第1次和第2次讀出來的記錄數不一樣。
從總的結果來看, 似乎不可重復讀和幻讀都表現為兩次讀取的結果不一致。但如果你從控制的角度來看, 兩者的區別就比較大。 對于前者, 只需要鎖住滿足條件的記錄。 對于后者, 要鎖住滿足條件及其相近的記錄。
隔離級別 | 含義 |
---|---|
ISOLATION_DEFAULT | 使用后端數據庫默認的隔離級別 |
ISOLATION_READ_UNCOMMITTED | 最低的隔離級別,允許讀取尚未提交的數據變更,可能會導致臟讀、幻讀或不可重復讀 |
ISOLATION_READ_COMMITTED | 允許讀取并發事務已經提交的數據,可以阻止臟讀,但是幻讀或不可重復讀仍有可能發生 |
ISOLATION_REPEATABLE_READ | 對同一字段的多次讀取結果都是一致的,除非數據是被本身事務自己所修改,可以阻止臟讀和不可重復讀,但幻讀仍有可能發生 |
ISOLATION_SERIALIZABLE | 最高的隔離級別,完全服從ACID的隔離級別,確保阻止臟讀、不可重復讀以及幻讀,也是最慢的事務隔離級別,因為它通常是通過完全鎖定事務相關的數據庫表來實現的 |
對上表的一些解釋如下: |
1》ISOLATION_DEFAULT 使用后端數據庫默認的隔離級別。(ISOLATION [?a?s??le??n] 隔離)
2》ISOLATION_READ_UNCOMMITTED 最低的隔離級別,允許讀取尚未提交的數據變更,可能會導致臟讀、幻讀或不可重復讀
3》ISOLATION_READ_COMMITTED 允許讀取并發事務已經提交的數據,可以阻止臟讀,但是幻讀或不可重復讀仍有可能發生。(臟讀:發生在 一個事務讀取了,另一個事務改寫了但尚未提交到數據庫的數據時。因為改寫沒有提交到數據庫,所以可能會回滾。導致第一個事務讀到的值無效)
4》ISOLATION_REPEATABLE_READ 一個事務中,對同一字段的多次讀取結果都是一致的,除非數據是被本身事務自己所修改。可以阻止臟讀和不可重復讀,但幻讀仍有可能發生(不可重復讀:一個事務中執行多次相同的查詢時,讀取到的值不同,重點在于修改update)
5》ISOLATION_SERIALIZABLE 最高的隔離級別,完全服從ACID的隔離級別,確保阻止臟讀、不可重復讀以及幻讀,也是最慢的事務隔離級別,因為它通常是通過完全鎖定事務相關的數據庫表來實現的。(幻讀:一個事務中,2次或多次執行相同的查詢時,得到的結果的行數不一樣。重點在于增加insert和刪除delete)
事務的第三個特性是它是否為只讀事務。如果事務只對后端的數據庫進行該操作,數據庫可以利用事務的只讀特性來進行一些特定的優化。通過將事務設置為只讀,你就可以給數據庫一個機會,讓它應用它認為合適的優化措施。
為了使應用程序很好地運行,事務不能運行太長的時間。因為事務可能涉及對后端數據庫的鎖定,所以長時間的事務 會不必要地占用數據庫資源。事務超時就是事務的一個定時器,在特定時間內事務如果沒有執行完畢,那么就會自動回滾,而不是一直等待其結束。
事務五邊形的最后一個方面是一組規則,這些規則定義了哪些異常會導致事務回滾,而哪些不會。默認情況下,事務只有遇到運行期異常時才會回滾,而在遇到檢查型異常時不會回滾(這一行為與EJB的回滾行為是一致的) 但是你可以聲明事務在遇到特定的檢查型異常時像遇到運行期異常那樣回滾。同樣,你還可以聲明事務遇到特定的異常不回滾,即使這些異常是運行期異常。
Spring提供了對編程式事務和聲明式事務的支持。編程式事務允許用戶在代碼中精確定義事務的邊界,而聲明式事務(基于AOP)有助于用戶將操作與事務規則進行解耦。
簡單地說,編程式事務侵入到了業務代碼里面,但是提供了更加詳細的事務管理;而聲明式事務由于基于AOP,所以既能起到事務管理的作用,又可以不影響業務代碼的具體實現。(編程式事務放到了代碼里。聲明式事務放在AOP里面)
感謝各位的閱讀,以上就是“如何掌握Spring事務管理+事物隔離級別”的內容了,經過本文的學習后,相信大家對如何掌握Spring事務管理+事物隔離級別這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。