天天看點

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

一、事務的基礎知識

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

       在上面的事務特性中,資料“一緻性”是最終目标,其他的特性都是為達到這個目标的措施、要求和手段。注解:這句話是完全正确的。

      資料庫管理系統一般采用重執行日志保證原子性、一緻性和持久性,重執行日志記錄了資料庫變化的每一個動作,資料庫在一個事務中執行一部分操作後發生錯誤退出,資料庫即可以根據重執行日志撤銷已經執行的操作。此外,對于已經送出的事務,即使資料庫崩潰,在重新開機資料庫時也能夠根據日志對尚未持久化的資料進行相應的重執行操作。

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

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

二、JDBC對的事務支援

      在上面讨論了資料庫的事務機制之後,我應該去探究一下JDBC的事務了,畢竟我不能任何sql語句都寫在存儲過程裡,讓資料庫系統去自己去管理事務吧(我就經曆過這樣的項目,結果是存儲過程沒人敢修改,因為不知道這個存儲過程有沒有在别的地方被修改,代碼一團糟,人人都希望能夠重寫項目)。               我知道了資料庫的事務機制,但是我也知道,并不是所有資料庫系統都有事務支援的,mysql中插件式的存儲引擎中就有好幾個是不支援事務機制的。是以在最接近資料庫的應用程式--JDBC是怎麼來支援事務的呢?答案是手動支援。       代碼如下:        

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

      一如代碼中,這個是大家在學習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 包中。       下圖描述三者關系:         

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

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學習筆記---5-Spring事務管理(1)

   事務傳播:Spring定義了幾個傳播類型;    事務逾時:事務在逾時前運作多久,逾時時間後,事務被復原。    隻讀狀态:隻讀事務不修改任何資料。           Spring運作通過XML或注解中繼資料的方式為一個有事務要求的服務類方法配置事務屬性,這些資訊将作為Spring事務管理架構的”輸入“,Spring将自動按事務屬性資訊的訓示,為目标提供相應的事務支援。 解釋:上面的這段話讀着有點雲裡霧裡的,其實要表達的意思是:Spring的事務管理将會采用AOP的支援,為目标類提供事務支援。而配置的事務屬性會采用IOC,将屬性注入到目标類中。    IOC對配置的屬性支援,AOP對配置的目标方法,結合起來對Spring的事務管理進行支援。

五、Spring事務管理器實作類

      spring 将事務管理委托給底層具體的持久化實作架構完成,是以Spring為不同的持久化架構提供了PlatformTransactionManagerg接口的實作類。    如圖:

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

    這些事務管理器都是針對特定架構的,這樣,使用者就可以通過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中類型的事務傳播行為,它們規定了事務方法和事務方法發生嵌套調用時事務如何進行傳播,      如圖:

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

      當使用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等。