Spring學習筆記---5-Spring事務管理(1)

一、事務的基礎知識

      Spring提供了靈活方便Dev事務管理功能,這些功能是基於底層數據庫本身的事務處理機制工作的。那我們在瞭解Spring的事務管理和配置之前,先了解一下數據庫事務的基礎知識。
       事務有四大特性:原子性,一致性,隔離性、持久性等。
       原子性:指的是一個事務的最小的單位是原子,如果在一個數據庫語句中,有多個sql組成,則每條sql就是這個大sql的原子,如果有一條sql執行失敗,那就意味着這一大條的sql執行失敗,那麼之前執行過的sql就必須重新回滾到最初狀態,用最恰當的比喻就是“一榮俱榮,一損俱損”;如果成功,則整條語句都執行成功,否則都失敗,回到之前的狀態。
       一致性:大家都用轉賬的時候A賬戶和B賬戶之間的總的金額保持不變來說明一致性。註解:其實這句話的意思是如果事務沒有成功,則一定要完全回滾,如果成功了,則一定要保證數據的正確性。
      隔離性:在併發數據操作時,不同的事務擁有各自的數據空間,它們的操作不會被對方產生干擾。準確的說,並非要求做到完全無干擾,數據庫規定了各種事務隔離級別,不同隔離級別對應不同的干擾程度,隔離級別越高,數據一致性越好,但併發性越弱。註解:指的是事務與事務之間的無關性,不會因爲一個事務的發生去影響另一個事務的數據。
       持久性:一旦事務提交成功後,事務中所有的數據操作都必須被持久化到數據庫中,即使提交事務後,數據庫馬上崩潰,在數據庫重啓時,也必須保證能夠通過某種機制恢復數據。

       在上面的事務特性中,數據“一致性”是最終目標,其他的特性都是爲達到這個目標的措施、要求和手段。註解:這句話是完全正確的。

      數據庫管理系統一般採用重執行日誌保證原子性、一致性和持久性,重執行日誌記錄了數據庫變化的每一個動作,數據庫在一個事務中執行一部分操作後發生錯誤退出,數據庫即可以根據重執行日誌撤銷已經執行的操作。此外,對於已經提交的事務,即使數據庫崩潰,在重啓數據庫時也能夠根據日誌對尚未持久化的數據進行相應的重執行操作。

       和Java程序採用對象鎖機制進行線程同步類似,數據庫管理系統採用數據庫鎖機制保證事務的隔離性。當多個事務試圖對相同的數據進行操作時,只有持有鎖的事務才能操作數據,知道前一個事務完成後,後面的事務纔有機會對數據進行操作。

       註解:上面講的都是數據庫事務的實現,在數據庫系統中怎麼對每一條sql或者多條sql進行事務處理的:事務鎖機制--也就是鎖表或者鎖行機制;當前對同一行後者同一個表的操作只能是一個事務操作。
       問題是:這個是事務的基礎知識,我是要通過應用程序管理事務來對數據庫進行操作,我知道了數據庫的事務,那跟我學習應用程序管理事務有什麼關係?請看下面?

二、JDBC對的事務支持

      在上面討論了數據庫的事務機制之後,我應該去探究一下JDBC的事務了,畢竟我不能任何sql語句都寫在存儲過程裏,讓數據庫系統去自己去管理事務吧(我就經歷過這樣的項目,結果是存儲過程沒人敢修改,因爲不知道這個存儲過程有沒有在別的地方被修改,代碼一團糟,人人都希望能夠重寫項目)。
       
      我知道了數據庫的事務機制,但是我也知道,並不是所有數據庫系統都有事務支持的,mysql中插件式的存儲引擎中就有好幾個是不支持事務機制的。所以在最接近數據庫的應用程序--JDBC是怎麼來支持事務的呢?答案是手動支持。
      代碼如下:
       
      一如代碼中,這個是大家在學習Java時都會學到的一段代碼,先鏈接鏈接,然後建立一個sql對象,然後執行sql。在上面的代碼中增加幾行代碼:關閉自動提交的機制,設置了事務隔離級別,提交事務,並回滾事務。
   
       補充:Connection默認情況下是自動提交的,即每條執行的sql都對應一個事務。爲了將多條sql當做一個事務來執行,則必須阻止其自動提交:conn.setAutoCommit(false); 

       其中的conn.commit();就是提交事務,如果提交失敗了,則回滾:conn.rollback();

       問題來了:我執行了conn.commit(); 是怎麼提交的?
                       我執行了conn.rollback(); 又是怎麼回滾的?怎麼做到的呢?   
       這個問題中所用到的JDBC其實是將配置文件中的數據庫連接池中的信息,一條sql就是使用數據庫連接池中的一個連接,一個事務。如果能夠做到,如果在事務提交時,如果失敗,執行回滾的話,其實調用的是數據庫本身的回滾機制。

三、Spring是事務管理的支持

      Spring爲事務管理提供了一致的編程模型,在高層次建立了統一的事務抽象。也就是說無論是SpringJDBC、Hibernate或者其他的工具,Spring都讓用戶可以用統一的編程模型進行事務管理(天下一統)。
      Spring事務管理繼承了這一風格,也提供了事務模板類TransactionTemplate。通過TransactionTemplate 並配合使用事務回調TransactionCallback 指定具體的持久化操作就可以通過編程方式實現事務管理,而無須關注資源獲取,複用、釋放、事務同步和異常梳理的操作
       註解:也就是說Spring對事務管理進行統一管理,只需要採用Spring提供的模板:TransactionTemplate,即可。至於資源的獲取,複用,釋放,事務同步,異常處理等統統不用操心,Spring會幫我們做。

       如果你覺得到這裏已經覺得Spring真的是勞苦功高啊,彆着急,Spring還有更大的絕招:聲明式事務管理。Spring運行通過聲明方式,在IOC配置中指定事務的邊界和事務屬性,Spring自動在制定的事務邊界上應用事務屬性。這種聲明式事務一直是EJB引以爲傲的,現在Spring讓事務管理更加平民化。(到這裏就只剩下對Spring頂禮膜拜了吧)

      Spring認識到,在大部分的應用中我們都會使用單個的數據源,只有很少的應用會用到多數據源。因此在但數據源的情況下,Spring直接使用底層的數據管理事務。而如果我們用的是多數據源的JTA事務,Spring才需求JavaEE應用服務器的支持,通過引用應用服務器中的JNDI資源完成ITA事務。
  
      註解:無論我們採用的是但數據源還是多數據源,都可以使用Spring提供的相同的事務管理模型。 

四、事務管理關鍵抽象

      在Spring事務管理SPI (Service Privider Interface)的抽象層主要包括3個接口,分別是 PlatformTransactionManager、TransactionDefinition 和 TransactionStatus,他們位於 org.springframework.transaction 包中。
      下圖描述三者關係:
        
TransactionDefinition 用於描述事務的隔離級別、超時時間、是否爲只讀事務和事務傳播規則等控制事務具體行爲的事務屬性,這些事務屬性可以通過XML配置或註解描述提供,也可以通過手工編程的方式設置。
PlatformTransactionManagerg根據TransactionDefinition 提供的事務屬性配置信息,創建事務,並用TransactionStatus描述這個激活事務的狀態。
解釋:不要被上面的沒見過的Spring類給嚇着,你打開這個來就知道了,如下:
  1. public interface TransactionDefinition {
  2. int PROPAGATION_REQUIRED = 0;
  3. int PROPAGATION_SUPPORTS = 1;
  4. int PROPAGATION_MANDATORY = 2;
  5.       int PROPAGATION_REQUIRES_NEW = 3;
  6.      ……
  7.   }   
          TransactionDefinition 定了Spring兼容的事務屬性,這些屬性對事務管理控制的若干方面進行配置。
   事務隔離:當前事務和其他事務隔離的程度;如:
    
   事務傳播:Spring定義了幾個傳播類型;
   事務超時:事務在超時前運行多久,超時時間後,事務被回滾。
   只讀狀態:只讀事務不修改任何數據。
          Spring運行通過XML或註解元數據的方式爲一個有事務要求的服務類方法配置事務屬性,這些信息將作爲Spring事務管理框架的”輸入“,Spring將自動按事務屬性信息的指示,爲目標提供相應的事務支持。
解釋:上面的這段話讀着有點雲裏霧裏的,其實要表達的意思是:Spring的事務管理將會採用AOP的支持,爲目標類提供事務支持。而配置的事務屬性會採用IOC,將屬性注入到目標類中。
   IOC對配置的屬性支持,AOP對配置的目標方法,結合起來對Spring的事務管理進行支持。

五、Spring事務管理器實現類

      spring將事務管理委託給底層具體的持久化實現框架完成,因此Spring爲不同的持久化框架提供了PlatformTransactionManagerg接口的實現類。
   如圖:
   這些事務管理器都是針對特定框架的,這樣,用戶就可以通過Spring所提交的高級抽象對不同種類的事務使用相同的方式進行管理,而不用關心具體的實現。解釋:不同的框架使用不同的事務管理器。
  要實現事務管理,首先要在Spring中配置好相應的事務管理器,爲事務管理器指定數據資源以及一些其他事務管理控制屬性。

六、事務同步管理器

       Spring將JDBC的Connection、Hibernate的Session等訪問數據庫的鏈接或會話對象統稱爲資源。這些資源在同一時刻是不能多線程共享的(註解:防止線程中數據錯亂,必須不能共享),爲了讓Dao、Service類可能做到singleton,Spring的事務同步管理器類org.springframework.transaction.support.TransactionSynchronizationManager使用ThreadLocal管理爲不同事務線程提供了獨立的資源副本,同時維護事務配置的屬性和運行狀態信息。事務同步管理器是Spring事務管理的基石部分,不管用戶使用的是編程式事務管理,還是聲明式事務管理,都離不開事務同步管理器。
     Spring爲不同的持久化技術提供了模板類,模板類在內部通過資源獲取工具類間接訪問TransactionSynchronizationManager中的線程綁定資源。因此,如果Dao使用模板類進行持久化操作,這些Dao就可以配置成singleton。如果不適用模板類,也可直接通過資源獲取工具類訪問線程相關的資源。
     解釋:經驗,項目中很少會脫離模板類去獲取線程中資源的。

七、事務傳播行爲

      當調用一個基於Spring的Service接口方法(如UserService#addUser())時,它將運行與Spring管理的事務環境中,Service接口方法可能會在內部調用其他Service接口方法以共同完成一個完整的業務操作,因此就會產生服務接口方法嵌套調用的情況,Spring通過事務傳播行爲控制當前的事務如何傳播到被嵌套的目標服務接口方法中。事務傳播是Spring進行事務管理的重要概念。
      Spring在TransactionDefinition接口中規定了7中類型的事務傳播行爲,它們規定了事務方法和事務方法發生嵌套調用時事務如何進行傳播,
     如圖:
              
      當使用PROPAGATION_NESTED時,底層的數據源必須基於JDBC3.0,並且實現者需要支持保存點事務機制。


八、設計原理和基本過程

          在使用Spring聲明式事務處理的時候,一種常用的方法是結合IOC容器和Spring已有的TransactionProxyFactoryBean對事務管理進行配置,比如,可以在這個TransactionProxyFactoryBean中爲事務方法配置傳播行爲、併發事務隔離級別等事務處理屬性,從而對聲明式事務的處理提供指導。聲明式事務處理的實現大致可以分爲以下幾個部分:
        1、讀取和處理在IOC容器中配置的事務處理屬性,並轉化爲Spring事務處理需要的內部數據結構。具體來說,這裏涉及的類是TransactionAttributeSourceAdvisor,從名字可以看出,它是一個AOP通知器,Spring使用這個通知器來完成對事務處理屬性值的處理。處理的結果是,在IOC容器中配置的事務處理屬性信息,會被讀入並轉化成TransactionAttribute表示的數據對象,這個數據對象是Spring對事務處理屬性值的數據抽象,對這些屬性的處理時和TransactionProxyFactoryBean攔截下來的事務方法的處理結合起來的。
        2、Spring事務處理模塊實現統一的事務處理過程。這個通用的事務處理過程包含處理事務配置屬性,以及與線程綁定完成事務處理的過程。Spring通過TransactionInfo和TransactionStatus這兩個數據對象,在事務處理過程中記錄和傳遞相關執行場景。
        3、底層的事務處理實現。對於底層的事務操作,Spring委託給具體的事務處理器來完成,這些具體的事務處理器,就是在IOC容器中配置聲明式事務處理時,配置的PlatformTransactionManager的具體實現,比如DataSourceTransactionManager和HibernateTransactionManager等。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章