1. 程式人生 > >spring 事務

spring 事務

需要 意思 會有 都是 讀取 有用 lac 邏輯 有效



1) PROPAGATION_REQUIRED ,默認的spring事務傳播級別,使用該級別的特點是,如果上下文中已經存在事務,那麽就加入到事務中執行,如果當前上下文中不存在事務,則新建事務執行。所以這個級別通常能滿足處理大多數的業務場景。


2)PROPAGATION_SUPPORTS ,從字面意思就知道,supports,支持,該傳播級別的特點是,如果上下文存在事務,則支持事務加入事務,如果沒有事務,則使用非事務的方式執行。所以說,並非所有的包在transactionTemplate.execute中的代碼都會有事務支持。這個通常是用來處理那些並非原子性的非核心業務邏輯操作。應用場景較少。


3)PROPAGATION_MANDATORY

, 該級別的事務要求上下文中必須要存在事務,否則就會拋出異常!配置該方式的傳播級別是有效的控制上下文調用代碼遺漏添加事務控制的保證手段。比如一段代碼不能單獨被調用執行,但是一旦被調用,就必須有事務包含的情況,就可以使用這個傳播級別。


4)PROPAGATION_REQUIRES_NEW ,從字面即可知道,new,每次都要一個新事務,該傳播級別的特點是,每次都會新建一個事務,並且同時將上下文中的事務掛起,執行當前新建事務完成以後,上下文事務恢復再執行。


問題 :如果其中一個子事務回滾了,父事務是否回滾?答案是不會,因為子事務是新建事務,父事務已經被掛起,兩者不會受到影響。

再問:如果父事務回滾了,子事務是否回滾?答案是不會,同樣的理由。但是可以手動控制一旦子事務回滾,父事務也回滾。


這是一個很有用的傳播級別,舉一個應用場景:現在有一個發送100個紅包的操作,在發送之前,要做一些系統的初始化、驗證、數據記錄操作,然後發送100封紅包,然後再記錄發送日誌,發送日誌要求100%的準確,如果日誌不準確,那麽整個父事務邏輯需要回滾。


怎麽處理整個業務需求呢?就是通過這個PROPAGATION_REQUIRES_NEW 級別的事務傳播控制就可以完成。發送紅包的子事務不會直接影響到父事務的提交和回滾。


5)PROPAGATION_NOT_SUPPORTED
,這個也可以從字面得知,not supported ,不支持,當前級別的特點就是上下文中存在事務,則掛起事務,執行當前邏輯,結束後恢復上下文的事務。


這個級別有什麽好處?可以幫助你將事務極可能的縮小。我們知道一個事務越大,它存在的風險也就越多。所以在處理事務的過程中,要保證盡可能的縮小範圍。比如一段代碼,是每次邏輯操作都必須調用的,比如循環1000次的某個非核心業務邏輯操作。這樣的代碼如果包在事務中,勢必造成事務太大,導致出現一些難以考慮周全的異常情況。所以這個事務這個級別的傳播級別就派上用場了。用當前級別的事務模板抱起來就可以了。


6)PROPAGATION_NEVER ,該事務更嚴格,上面一個事務傳播級別只是不支持而已,有事務就掛起,而PROPAGATION_NEVER傳播級別要求上下文中不能存在事務,一旦有事務,就拋出runtime異常,強制停止執行!這個級別上輩子跟事務有仇。


7)PROPAGATION_NESTED
,字面也可知道,nested,嵌套級別事務。該傳播級別特征是,如果上下文中存在事務,則嵌套事務執行,如果不存在事務,則新建事務。

那麽什麽是嵌套事務呢?很多人都不理解,我看過一些博客,都是有些理解偏差。

嵌套是子事務套在父事務中執行,子事務是父事務的一部分,在進入子事務之前,父事務建立一個回滾點,叫save point,然後執行子事務,這個子事務的執行也算是父事務的一部分,然後子事務執行結束,父事務繼續執行。重點就在於那個save point。看幾個問題就明了了:

如果子事務回滾,會發生什麽?

父事務會回滾到進入子事務前建立的save point,然後嘗試其他的事務或者其他的業務邏輯,父事務之前的操作不會受到影響,更不會自動回滾。


如果父事務回滾,會發生什麽?

父事務回滾,子事務也會跟著回滾!為什麽呢,因為父事務結束之前,子事務是不會提交的,我們說子事務是父事務的一部分,正是這個道理。那麽:


事務的提交,是什麽情況?

是父事務先提交,然後子事務提交,還是子事務先提交,父事務再提交?答案是第二種情況,還是那句話,子事務是父事務的一部分,由父事務統一提交。


現在你再體會一下這個”嵌套“,是不是有那麽點意思?


以上是事務的7個傳播級別,在日常應用中,通常可以滿足各種業務需求,但是除了傳播級別,在讀取數據庫的過程中,如果兩個事務並發執行,那麽彼此之間的數據是如何影響的呢?

這就需要了解一下事務的另一個特性:數據隔離級別

數據隔離級別分為不同的四種:


1、Serializable :最嚴格的級別,事務串行執行,資源消耗最大;

2、REPEATABLE READ :保證了一個事務不會修改已經由另一個事務讀取但未提交(回滾)的數據。避免了“臟讀取”和“不可重復讀取”的情況,但是帶來了更多的性能損失。

3、READ COMMITTED :大多數主流數據庫的默認事務等級,保證了一個事務不會讀到另一個並行事務已修改但未提交的數據,避免了“臟讀取”。該級別適用於大多數系統。

4、Read Uncommitted :保證了讀取過程中不會讀取到非法數據。

上面的解釋其實每個定義都有一些拗口,其中涉及到幾個術語:臟讀、不可重復讀、幻讀。
這裏解釋一下:

臟讀 :所謂的臟讀,其實就是讀到了別的事務回滾前的臟數據。比如事務B執行過程中修改了數據X,在未提交前,事務A讀取了X,而事務B卻回滾了,這樣事務A就形成了臟讀。

不可重復讀 :不可重復讀字面含義已經很明了了,比如事務A首先讀取了一條數據,然後執行邏輯的時候,事務B將這條數據改變了,然後事務A再次讀取的時候,發現數據不匹配了,就是所謂的不可重復讀了。

幻讀 :小的時候數手指,第一次數十10個,第二次數是11個,怎麽回事?產生幻覺了?
幻讀也是這樣子,事務A首先根據條件索引得到10條數據,然後事務B改變了數據庫一條數據,導致也符合事務A當時的搜索條件,這樣事務A再次搜索發現有11條數據了,就產生了幻讀。

spring 事務