Spring框架事務支持模型的優點

全局事務

全局事務支持對多個事務性資源的操做,一般是關係型數據庫和消息隊列。應用服務器經過JTA管理全局性事務,API很是煩瑣。UserTransaction一般須要從JNDI獲取,意味着須要與JNDI綁定在一塊兒,且JTA通常只在應用服務器可用,下降了應用代碼的可重用性。java

本地事務

本地事務面向具體的資源,例如與JDBC鏈接關聯的事務。本地事務易於使用,但不能跨多個事務性資源。使用JDBC管理事務的代碼不能在全局JTA事務中運行,所以不能確保跨多個資源的正確性。且本地事務侵入了編程模型。spring

Spring的一致性編程模型

Spring讓開發者在任何環境下均可以使用一致性的編程模型,編寫一次代碼,就能夠在不一樣環境的不一樣事務管理策略中運行。Spring提供聲明式和編程式事務管理,大多數人選擇聲明式,這也是推薦的方式。數據庫

使用編程式事務管理時,開發者使用的是Spring框架的事務抽象,它能夠運行在任何底層事務設施之上。使用聲明式事務管理,開發者只須要編寫少許甚至不須要編寫事務相關代碼,所以應用代碼不依賴Spring框架事務API或其它事務API。apache

Spring的事務管理支持從傳統規則到應用服務器的轉換。編程

一般只有在經過EJB進行聲明式事務時才真的須要應用服務器。實際上即便應用服務器有JTA的功能,也能夠認爲Spring框架的聲明式事務比EJB CMT更增強大,更加能提升效率。服務器

只有在應用須要跨多個資源處理事務時才須要應用服務器的JTA功能。許多高級應用使用單個高可擴展的數據庫(例如Oracle RAC)來代替。獨立的事務管理器也是一種方案,例如Atomikos Transactions、JOTM。應用也可能須要其它的應用服務器功能,例如JMS、JCA。session

Spring框架讓開發者決定什麼時候把應用擴展爲完整的應用服務器,只須要在配置文中修改某些Bean定義便可。app

理解Spring框架的事務抽象

事務策略是Spring事務抽象的關鍵。事務策略由org.springframework.transaction.PlatformTransactionManager接口定義:框架

public interface PlatformTransactionManager {
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
    void commit(TransactionStatus status) throws TransactionException;
    void rollback(TransactionStatus status) throws TransactionException;
}
工具

這是一個服務提供商接口(SPI),雖然能夠在應用中編程式地使用。因爲這是一個接口,因此能夠很容易被模擬出來。它並不與JNDI這樣的查找策略綁定在一塊兒。它能夠像其它bean同樣在Spring框架IoC容器中被定義。即便在使用JTA的場景下,也能夠從Spring框架的事務中受益,由於Spring中的事務代碼比直接使用JTA的更加容易測試。

TransactionException是做爲非檢查異常拋出,它擴展java.lang.RuntimeException類,由於在Spring的角度看來,事務設施故障幾乎老是致命的,不多狀況下應用能夠從事務故障中恢復。開發者能夠選擇捕獲這個異常並做處理,但並不強制這樣作。

getTransaction(…)根據TransactionDefinition類型的參數返回一個TransactionStatus對象,所返回的對象可能表明一個新的事務,也多是一個當前調用棧中已經存在的事務。後一種狀況表示,在使用Java EE事務上下文時,一個TransactionStatus是與執行線程關聯的。

TransactionDefinition接口

TransactionDefinition接口指定了:

  • 隔離級別(Isolation):一個事務與其它事務的隔離級別,例如一個事務是否可看到其它事務未提交的寫操做
  • 傳播性(Propagation):通常全部在一個事務中運行的代碼都會處於一個事務中,但當執行一個方法而且事務環境已經存在時,能夠指定此時的行爲。例如所調用方法內的代碼繼續運行在已經存在的事務中(常見狀況),或者暫停當前事務並建立一個新的事務來運行所調用方法內的代碼。Spring提供了全部EJB CMT所提供的事務傳播選項。
  • 超時(Timeout):在事務超時並被底層事務設施自動回滾前,這個事務能夠運行多久。
  • 只讀狀態(Read-only):當代碼不修改數據時,可使用只讀事務。只讀事務在某些場景下頗有用,例如使用Hibernate時。

以上設置是標準的事務概念,指的就是事務隔離級別及其它核心事務概念。理解這些概念是使用Spring框架事務管理或其它事務解決方案的基礎。

TransactionStatus接口

TransactionStatus接口爲事務性代碼提供控制事務執行和查詢事務狀態的簡便方式。這些概念必需要熟悉,它們是全部事務API都共同的東西:

public interface TransactionStatus extends SavepointManager {
    boolean isNewTransaction();
    boolean hasSavepoint();
    void setRollbackOnly();
    boolean isRollbackOnly();
    void flush();
    boolean isCompleted();
}

在Spring中無論理使用聲明式事務仍是編程式事務,定義正確的PlatformTransactionManager實現都是必須的,通常經過DI進行定義。

PlatformTransactionManager通常只須要知道本身的工做環境:JDBC、JTA、Hibernate等等。下面是定義一個本地PlatformTransactionManager實現的例子:

定義JDBC數據源:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
</bean>

相關的PlatformTransactionManager引用DataSource定義:

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
若是在Java EE容器中使用容器DataSource,則經過JNDI獲取,並與Spring的JtaTransactionManager關聯:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/jee
        http://www.springframework.org/schema/jee/spring-jee.xsd">
    <jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/>
    <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
    <!-- other <bean/> definitions here -->
</beans>

 

Hibernate事務配置

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mappingResources">
        <list>
            <value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <value>
            hibernate.dialect=${hibernate.dialect}
        </value>
    </property>
</bean>

<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

 

若是使用Hibernate和Java EE容器管理的JTA事務,則與前面對JDBC的JTA配置同樣:

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mappingResources">
        <list>
            <value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <value>
            hibernate.dialect=${hibernate.dialect}
        </value>
    </property>
</bean>

<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
若是使用JTA,則無論使用什麼樣的數據訪問技術(JDBC、Hibernate JPA、或其它支持的技術),事務管理器定義會以相同的方式進行查找,由於JTA事務是全局性的,它會證募全部的事務性資源(JDBC connection、SessionFactory等等)。
 
經過這種配置方式,本地和全局事務的轉換不須要修改應用代碼,只須要在配置文件上作修改。
 

使用事務同步資源

高級別同步方式

優先使用的是Spring高級別的基於模板的持久化集成API,或使用帶有事務感知的工廠Bean的原生ORM API,或者管理原生資源工廠的代理。這些事務感知的方案在內部處理對資源的建立、重用、清理、可選的資源事務同步、異常映射,所以用戶代碼不須要作這些工做,只須要關注於自身的持久化邏輯。通常對JDBC的訪問使用的是JdbcTemplate模板方式,或ORM原生API。

低級別同步方式

JDBC的DataSourceUtils、JPA的EntityManagerFactoryUtils、Hibernate的SessionFactoryUtils、JDO的PersistemceManagerFactoryUtils是低級別的操做工具。若是應用代碼須要直接處理原生持久化API的資源類型時,可使用這些類來確保獲取正確的由Spring框架管理的實例、事務被正確同步、異常被正確映射到一致的API。

例如對於傳統的JDBC,可使用下面的代碼代替對DataSource的getConnection()方法的調用:

Connection conn = DataSourceUtils.getConnection(dataSource);
上面的代碼,若是一個已經存在的事務已經有一個同步connection與其關聯,則這個connection會被返回,不然會建立一個新的鏈接,而且會同步到已經存在的事務,且在後繼對同一個事務的使用中能夠重用這個鏈接。上面調用中,底層拋出的SQLException被Spring框架包裝成CannotGetJdbcConnectionException,一個非檢查DataAccessException,這比單純的SQLException可以提供更多的信息,並確保跨數據庫甚至跨不一樣持久化持久的可移植性。
 
上面的代碼在沒有Spring事務管理的狀況下也是可用的。
 
在使用Spring的JDBC支持、JPA支持、Hibernate支持時,多數人更願意使用Spring的事務抽象,而不是直接使用相似DataSourceUtils這樣的輔助類。例如使用JdbcTemplate來簡化JDBC的使用,它會自動爲應用獲取正確的鏈接。
 

TransactionAwareDataSourceProxy

在最低層存在一個TransactionAwareDataSourceProxy類,它是DataSource的代理類,包裝了DataSource,以添加Spring事務管理的感知功能,相似於由Java EE服務器提供的事務性JNDI DataSource。

除非現存代碼必須經過傳遞一個標準的JDBC DataSource實現進行調用,不然這個類不該該被使用。

相關文章
相關標籤/搜索