spring transaction源碼分析--事務架構

1. 引言 事務特性

事務是併發控制的單元,是用戶定義的一個操做序列。這些操做要麼都作,要麼都不作,是一個不可分割的工做單位。經過事務將邏輯相關的一組操做綁定在一塊兒,以便服務器 保持數據的完整性。事務一般是以begin transaction開始,以commit或rollback結束。Commint表示提交,即提交事務的全部操做。具體地說就是將事務中全部對數據的更新寫回到磁盤上的物理數據庫中去,事務正常結束。Rollback表示回滾,即在事務運行的過程當中發生了某種故障,事務不能繼續進行,系統將事務中對數據庫的全部已完成的操做所有撤消,滾回到事務開始的狀態。html

  原子性(Atomic) 對數據的修改要麼所有執行,要麼所有不執行。java

  一致性(Consistent) 在事務執行先後,數據狀態保持一致性。程序員

  隔離性(Isolated) 一個事務的處理不能影響另外一個事務的處理。spring

  持續性(Durable) 事務處理結束,其效果在數據庫中持久化。sql

  1. Java事務的類型
    Java事務的類型有三種:JDBC事務、JTA(Java Transaction API)事務、容器事務。
    一、JDBC事務數據庫

    JDBC 事務是用 Connection 對象控制的。JDBC Connection 接口( java.sql.Connection )提供了兩種事務模式:自動提交和手工提交。 java.sql.Connection 提供瞭如下控制事務的方法:編程

  public void setAutoCommit(boolean)
  public boolean getAutoCommit()
  public void commit()
  public void rollback()bootstrap

使用 JDBC 事務界定時,您能夠將多個 SQL 語句結合到一個事務中。JDBC 事務的一個缺點是事務的範圍侷限於一個數據庫鏈接。一個 JDBC 事務不能跨越多個數據庫。api

二、JTA(Java Transaction API)事務安全

JTA是一種高層的,與實現無關的,與協議無關的API,應用程序和應用服務器可使用JTA來訪問事務。

JTA容許應用程序執行分佈式事務處理——在兩個或多個網絡計算機資源上訪問而且更新數據,這些數據能夠分佈在多個數據庫上。JDBC驅動程序的JTA支持極大地加強了數據訪問能力。

若是計劃用 JTA 界定事務,那麼就須要有一個實現 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驅動程序。一個實現了這些接口的驅動程序將能夠參與 JTA 事務。一個 XADataSource 對象就是一個 XAConnection 對象的工廠。 XAConnection s 是參與 JTA 事務的 JDBC 鏈接。

您將須要用應用服務器的管理工具設置 XADataSource .從應用服務器和 JDBC 驅動程序的文檔中能夠了解到相關的指導。

J2EE應用程序用 JNDI 查詢數據源。一旦應用程序找到了數據源對象,它就調用 javax.sql.DataSource.getConnection() 以得到到數據庫的鏈接。

XA 鏈接與非 XA 鏈接不一樣。必定要記住 XA 鏈接參與了 JTA 事務。這意味着 XA 鏈接不支持 JDBC 的自動提交功能。同時,應用程序必定不要對 XA 鏈接調用 java.sql.Connection.commit() 或者 java.sql.Connection.rollback() .

相反,應用程序應該使用 UserTransaction.begin()、 UserTransaction.commit() 和 serTransaction.rollback() .

三、容器事務

容器事務主要是J2EE應用服務器提供的,容器事務大可能是基於JTA完成,這是一個基於JNDI的,至關複雜的API實現。相對編碼實現JTA事務管理, 咱們能夠經過EJB容器提供的容器事務管理機制(CMT)完成同一個功能,這項功能由J2EE應用服務器提供。這使得咱們能夠簡單的指定將哪一個方法加入事 務,一旦指定,容器將負責事務管理任務。這是咱們土建的解決方式,由於經過這種方式咱們能夠將事務代碼排除在邏輯編碼以外,同時將全部困難交給J2EE容 器去解決。使用EJB CMT的另一個好處就是程序員無需關心JTA API的編碼,不過,理論上咱們必須使用EJB.

四、三種Java事務差別

JDBC事務控制的侷限性在一個數據庫鏈接內,可是其使用簡單。

JTA事務的功能強大,事務能夠跨越多個數據庫或多個DAO,使用也比較複雜。

 容器事務,主要指的是J2EE應用服務器提供的事務管理,侷限於EJB應用使用。

五、應用場景

Java事務控制是構建J2EE應用不可缺乏的一部分,合理選擇應用何種事務對整個應用系統來講相當重要。通常說來,在單個JDBC 鏈接鏈接的狀況下能夠選擇JDBC事務,在跨多個鏈接或者數據庫狀況下,須要選擇使用JTA事務,若是用到了EJB,則能夠考慮使用EJB容器事務

  1. spring事務實現源碼分析

 3.1 dao模塊
    dao模塊定義了數據庫層的各類異常,其中異常的結構已經在spring-jdbc模塊中介紹過了,在這裏主要是dao的支持和異常的轉譯,其數據庫支持和轉譯結構以下所示:
spring transaction源碼分析--事務架構
dao 支持
提供了對hibernate、jdbc,cci的支持。咱們都想到熟悉,對cci可能有些陌生,下面的章節會講到。
dao異常轉譯
PersistenceExceptionTranslationPostProcessor:自動將標示爲@repository的bean的持久化異常進行轉譯。它增長一個PersistenceExceptionTranslationAdvisor來代理相應的已經存在的aop代理或者實現了目標接口的新產生的代理。它將本地資源異常轉換爲spring的DataAccessException及其子類上。

PersistenceExceptionTranslationAdvisor是一個spring aop的異常轉譯類,它應用到respository層或者dao層。它基於給定的PersistenceExceptionTranslator來將本地持久化異常轉換爲spring的DataAccessException族。

 PersistenceExceptionTranslationInterceptor:一個aop 方法攔截器(MethodInterceptor).提供基於PersistenceExceptionTranslator的異常轉換,它是PersistenceExceptionTranslator的代理,將運行時拋出的異常轉換爲spring 的DataAccessException族。

PersistenceExceptionTranslator spring集成其它數據獲取技術(如jpa、toplink、jdo、hibernate等)拋出運行時異常的接口。

3.2 jca模塊

  1. cci模塊

    spring transaction源碼分析--事務架構

J2EE提供JCA(Java Connector Architecture)規範來標準化對EIS(Enterprise Information System)的訪問。這個規範被分爲幾個不一樣的部分:

  SPI(Service provider interfaces)是鏈接器提供者(connector provider)必須實現的接口。 這些接口組成了一個能被部署在J2EE應用服務器上的資源適配器(resource adapter)。 在這種狀況下,由服務器來管理鏈接池(connection pooling)、事務和安全(託管模式(managed mode))。 應用服務器還負責管理客戶端應用程序以外所擁有的配置。鏈接器(connector)一樣能在脫離應用服務器的狀況下使用;在這種狀況下,應用程序必須直接對它進行配置(非託管模式(non-managed mode))。

  CCI (Common Client Interface)是應用程序用來與鏈接器交互並與EIS通訊的接口。一樣還爲本地事務劃界提供了API。

  Spring對CCI的支持,目的是爲了提供以典型的Spring方式來訪問CCI鏈接器的類,並有效地使用Spring的通用資源和事務管理工具。

注意:
鏈接器的客戶端沒必要老是使用CCI。 某些鏈接器暴露它們本身的API,只提供JCA資源適配器(resource adapter) 以使用J2EE容器的某些系統契約(system contracts)(鏈接池(connection pooling),全局事務(global transactions),安全(security))。 Spring並無爲這類鏈接器特有(connector-specific)的API提供特殊的支持。

  1. context模塊
    ResourceAdapterApplicationContext:一個jca ResourceAdapter的applicationContext實現,須要於jca的bootstrapContext一同初始化,最後傳遞到實現了BootstrapContextAware的spring 受管理bean。
    spring transaction源碼分析--事務架構
@Override    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        beanFactory.addBeanPostProcessor(new BootstrapContextAwareProcessor(this.bootstrapContext));
        beanFactory.ignoreDependencyInterface(BootstrapContextAware.class);
        beanFactory.registerResolvableDependency(BootstrapContext.class, this.bootstrapContext);        // JCA WorkManager resolved lazily - may not be available.
        beanFactory.registerResolvableDependency(WorkManager.class, new ObjectFactory<WorkManager>() {
                @Override            public WorkManager getObject() {                return bootstrapContext.getWorkManager();
                }
        });
}

spring transaction源碼分析--事務架構
BootstrapContextAwareProcessor:傳遞BootstrapContext到實現了BootStrapContextAware接口的spring bean。它在內部bean factory中自動註冊。
BootstrapContextAware:須要通知BootStrapContext的實現類。
BootstrapContext:提供一種機制,這種機制將一個Bootstrap的上下文傳遞到一個資源適配器實例。
3.endpoint模塊
AbstractMessageEndpointFactory:實現了jca 1.五、1.六、1.7版本的javax.resource.spi.endpoint.MessageEndpointFactory接口,它提供了事務管理能力。
GenericMessageEndpointFactory實現了抽象方法,對任意類型的消息監聽對象(javax.jms.MessageListener)或者javax.resource.cci.MessageListener對象提供了事務管理的能力。
GenericMessageEndpointManager管理類,對上述方法進行管理。
4.support模塊
LocalConnectionFactoryBean:建立一個本地JCA鏈接工廠。
ResourceAdapterFactoryBean :使用BootStrapContext啓動一個jca 1.5指定的ResouceAdapter。

  1. work模塊
    結構以下:
    spring transaction源碼分析--事務架構
    WorkManager提供了提交Work(Work繼承了Runnable)可執行實例的便利類。
    3.3 transaction模塊

spring事務架構

3.3.1 事務管理PlatformTransactionManager的架構

以下圖所示:

PlatformTransactionManager:spring事務的核心接口。

spring transaction源碼分析--事務架構

3.3.2 事務定義TransactionDefinition的架構

以下圖所示:
spring transaction源碼分析--事務架構

TransactionDefinition:定義spring容器事務屬性的接口。

包括事務傳播行爲類型和事務隔離級別:

事務傳播行爲類型

事務傳播行爲類型

說明

PROPAGATION_REQUIRED

若是當前沒有事務,就新建一個事務,若是已經存在一個事務中,加入到這個事務中。這是最多見的選擇。

PROPAGATION_SUPPORTS

支持當前事務,若是當前沒有事務,就以非事務方式執行。

PROPAGATION_MANDATORY

使用當前的事務,若是當前沒有事務,就拋出異常。

PROPAGATION_REQUIRES_NEW

新建事務,若是當前存在事務,把當前事務掛起。

PROPAGATION_NOT_SUPPORTED

以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。

PROPAGATION_NEVER

以非事務方式執行,若是當前存在事務,則拋出異常。

PROPAGATION_NESTED

若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則執行與PROPAGATION_REQUIRED相似的操做。

當使用PROPAGATION_NESTED時,底層的數據源必須基於JDBC 3.0,而且實現者須要支持保存點事務機制。

隔離級別:

爲了不上面出現幾種狀況在標準SQL規範中定義了4個事務隔離級別,不一樣隔離級別對事務處理不一樣

  1. 未受權讀取(Read Uncommitted):也稱未提交讀。防止更新丟失(這不對應一級鎖嗎),若是一個事務已經開始寫數據則另一個數據則不容許同時進行寫操做但容許其餘事務讀此行數據。該隔離級別能夠經過「排他寫鎖」實現。事務隔離的最低級別,僅可保證不讀取物理損壞的數據。與READ COMMITTED 隔離級相反,它容許讀取已經被其它用戶修改但還沒有提交肯定的數據。

  2. 受權讀取(Read Committed):也稱提交讀。1之上防止髒讀取(這不對應二級鎖嗎)。這能夠經過「瞬間共享讀鎖」和「排他寫鎖」實現,讀取數據的事務容許其餘事務繼續訪問該行數據,可是未提交寫事務將會禁止其餘事務訪問該行。SQL Server 默認的級別。在此隔離級下,SELECT 命令不會返回還沒有提交(Committed) 的數據,也不能返回髒數據。

  3. 可重複讀取(Repeatable Read):2之上防止不可重複讀取(這不對應三級鎖嗎)。可是有時可能出現幻影數據,這能夠經過「共享讀鎖」和「排他寫鎖」實現,讀取數據事務將會禁止寫事務(但容許讀事務),寫事務則禁止任何其餘事務。在此隔離級下,用SELECT 命令讀取的數據在整個命令執行過程當中不會被更改。此選項會影響系統的效能,非必要狀況最好不用此隔離級。

  三級封鎖協議並不能阻止幻讀,修改的不能再被讀取,可是新增(刪除)的記錄數能夠統計。

  4. 串行(Serializable):也稱可串行讀(這不對應兩段鎖嗎)。提供嚴格的事務隔離,它要求事務序列化執行,事務只能一個接着一個地執行,但不能併發執行。若是僅僅經過 「行級鎖」是沒法實現事務序列化的,必須經過其餘機制保證新插入的數據不會被剛執行查詢操做事務訪問到。事務隔離的最高級別,事務之間徹底隔離。若是事務在可串行讀隔離級別上運行,則能夠保證任何併發重疊事務均是串行的。

點擊查看大圖
spring transaction源碼分析--事務架構
  LU丟失更新 DR髒讀 NRR非重複讀SLU二類丟失更新 PR幻像讀

爲了解決與「多個線程請求相同數據」相關的問題,事務之間用鎖相互隔開。多數主流的數據庫支持不一樣類型的鎖;所以,JDBC API 支持不一樣類型的事務,它們由 Connection 對象指派或肯定。
爲了在性能與一致性之間尋求平衡纔出現了上面的幾種級別。事務保護的級別越高,性能損失就越大。
假定您的數據庫和 JDBC 驅動程序支持這個特性,則給定一個 Connection 對象,您能夠明確地設置想要的事務級別:
conn.setTransactionLevel(TRANSACTION_SERIALIZABLE) ;
能夠經過下面的方法肯定當前事務的級別:
int level = conn.getTransactionIsolation();
SavepointManager:管理事務savepoint的編程式API接口。

JDBC定義了SavePoint接口,提供在一個更細粒度的事務控制機制。當設置了一個保存點後,能夠rollback到該保存點處的狀態,而不是rollback整個事務。Connection接口的setSavepoint和releaseSavepoint方法能夠設置和釋放保存點。

TransactionStatus:事務狀態表現形式。

spring transaction源碼分析--事務架構

3.3.3 spring事務實現機制

1 高層

比較好的方式有:1.基於持久層api的模板方法;2.使用具備事務工廠bean的本地ORM api;3使用代理管理本地資源工廠。

2 底層

DataSourceUtils (用做JDBC事務), EntityManagerFactoryUtils (用做JPA事務), SessionFactoryUtils (用做Hibernate事務),PersistenceManagerFactoryUtils (用做JDO事務)等等,

例如:在使用jdbc時,你能夠不經過DataSource的getConnection()方法獲取connection,而是使用如下方法獲取:

Connection conn = DataSourceUtils.getConnection(dataSource);
3 最低層
TransactionAwareDataSourceProxy是事務的最底層,它代理了DataSource,並增長了spring管理事務功能。
參考資料:
1.http://www.educity.cn/rk/457230.html

  1. http://uule.iteye.com/blog/1445678
  2. http://zhxing.iteye.com/blog/368110
相關文章
相關標籤/搜索