本文是<實現 Spring 的事務控制>系列文章中一篇。本文假設讀者已經閱讀並理解《實現 Spring 的事務控制,之一(必要的概念)》文中所涉及的概念(當前鏈接、引用計數),以及數據庫鏈接的(new狀態) 數據庫
若是當前存在事務則掛起當前事務,並開啓一個全新的事務。新事務與已存在的事務之間彼此沒有關係。 spa
REQUIRES_NEW 行爲強調了獨立性。它保證了每一個事務狀態管理範圍內鎖使用的數據庫鏈接是彼此不同的。例如獨立事務會知足「A事務中存在B事務,當B事務遞交的時候不影響A事務。A,B兩個事務之間不存在相互關聯關係。「 .net
時間 | 事務1 | 事務2 |
T1 | 開始事務 | |
T2 | 操做1... | |
T3 | |
開始事務 |
T4 | 操做2... | |
T5 | 遞交事務 | |
T6 | |
回滾事務 |
定義中提到」掛起事務「這句話怎麼理解? 線程
所謂「掛起」指的是將當前線程使用的數據庫鏈接,暫時保存起來不在使用。取而代之的是一個新的數據庫庫鏈接。 對象
與掛起相對應的還有一個「恢復事務」,它們的操做是成對出現的。恢復就是將當前數據庫鏈接釋放掉,而後將之前掛起的那個數據庫鏈接從新設爲當前數據庫鏈接。 blog
REQUIRES_NEW 行爲因爲出現了「掛起」這樣的操做,所以它也帶來了一個全新的事務狀態叫「Suspent」。 接口
首先,Suspent 特徵只會出如今兩種重播行爲中 事務
獨立事務(REQUIRES_NEW) ci
非事務方式(NOT_SUPPORTED) get
如今讓咱們看一看具備 Suspent 特徵的事務究竟有什麼特殊的。首先要想產生 Suspent 特徵須要知足下面這樣的條件。
當前事務狀態中不具有「new」特徵
在第一篇文章中介紹過,new狀態是「標記當事務管理器建立新的事務狀態時,當前鏈接的事務狀態是如何的」。
咱們一瞧便知道,凡是不知足new狀態條件的那麼就只有一種可能了。在事務管理器建立事務對象的時候,當前鏈接已經開啓了事務。這也難怪,由於獨立事務的定義中第一句話就明白的寫着:「若是當前存在事務則掛起當前事務」。
咱們再往下看「並開啓一個全新的事務」這句話怎麼解釋?
這句話的前一句已經告訴咱們,若是存在事務就會掛起,而後在執行開啓新事務。這是因爲掛起事務以後,事務管理器會從新爲咱們申請一個新的數據庫鏈接。這個鏈接因爲還還沒有開啓數據庫事務,所以須要開啓。
事務管理器在建立 REQUIRES_NEW 行爲事務時,會取得當前鏈接這一過程會持有當前鏈接(引用計數+1)。注意:此時持有的數據庫鏈接並不必定是最終在操做階段使用的數據庫鏈接。
而後經過判斷當前鏈接是否存在事務狀態,來決定是否經過 執行掛起事務操做。一旦執行了掛起事務的操做就至關於清空了當前的數據庫鏈接。因此接下來須要從新申請一個數據庫鏈接,新申請的數據庫鏈接事務管理器也會持有它(引用計數+1)。
接下來隨後會經過 doBegin 方法爲這個新鏈接開啓事務,而這個新的鏈接偏偏知足了「new」狀態特徵。所以 REQUIRES_NEW 行爲事務中的事務狀態是具有「new」狀態的。但要注意,這個new狀態指的是當前鏈接,也就是後申請的那個數據庫鏈接事務狀態。
不管在開啓事務的時候Connection 此時此刻,能夠直接使用 Connection 接口暢快的使用數據庫操做。因爲每次進行數據庫操做都要反覆的申請和釋放數據庫鏈接。這會反覆的使引用計數 +1,-1。
在 REQUIRED 行爲中咱們知道,凡是具備 new 狀態的事務。在最後執行 commit & rollback 動做時都會真實的去執行它們。
可是在 REQUIRES_NEW 行爲中,除了真實遞交事務以外還會判斷事務中是否存在「Suspent」特徵。
在前面咱們知道在 REQUIRES_NEW 行爲下有可能會同時持有兩個數據庫鏈接的引用,所以在 cleanupAfter 過程當中雖然釋放了當前鏈接的引用計數,可是還有一個可能存在的掛起事務還沒處理。
爲此 REQUIRES_NEW 行爲不一樣於 REQUIRES 行爲的是增長了一個恢復掛起事務的過程,隨後又將掛起的事務引用釋放掉。