JTA分佈式事務實踐

最近一直在研究怎麼實現分佈式事務,花了很多時間,測試工程啓停測試了無數次,最終實現的時候其實也就是寫一些配置文件,對於工程代碼沒什麼影響。目前研究還不是很深刻,對於全面崩潰恢復如何實現和測試還不清楚。本文先介紹基礎的實現。 java

 

當業務須要在一個事務中操做多個不一樣的資源,例如多個數據庫,消息隊列,緩存等,那麼就須要使用分佈式事務了。在Java中通常建議使用JTA,這樣開發人員就不用關心什麼叫XA協議,什麼是兩階段提交協議。要使用JTA須要容器的支持,例如使用JBOSS,WebSphere;或者使用第三方組件例如JOTMAtomikos spring

 

JBOSS AS如今更名叫Wildfly了,以便和JBOSS EAP區分,後文我也改叫WildflyJOTM看起來是個死項目,我不打算使用。 數據庫

 

因爲目前開發框架基於spring+JPA設計,因此本文的配置主要是在spring中。其實用EJB的話配置更簡單,但須要容器支持。 api

 

1、Wildfly中配置JTA

一、配置數據庫驅動(oracle

a)         首先按照如下路徑新增目錄: 緩存

wildfly-9.0.0.CR1\modules\system\layers\base\com\oracle\ojdbc14\main tomcat

b)         把驅動文件ojdbc14.jar複製到此目錄下 session

c)         main目錄下新增配置文件module.xml oracle

mudule.xml 框架

<?xml version="1.0" encoding="UTF-8"?> dom

<module xmlns="urn:jboss:module:1.1" name="com.oracle.ojdbc14">

    <resources>

        <resource-root path="ojdbc14.jar"/>

    </resources>

    <dependencies>

        <module name="javax.api"/>

        <module name="javax.transaction.api"/>

    </dependencies>

</module>

 

打開wildflystandalone.xml配置文件(使用standalone模式啓動,domain模式還沒嘗試),找到<subsystem xmlns="urn:jboss:domain:datasources:3.0">配置項目,在<drivers>裏增長oracle驅動

增長

<driver name="oracle" module="com.oracle.ojdbc14">

    <driver-class>oracle.jdbc.OracleDriver</driver-class>

    <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>

</driver>

 

二、配置XA數據源

配置兩個xa的數據源,暫時都是數據庫,之後學會JMS後再加上。

 

配置 1.2.1  oracle數據源-intf

<xa-datasource jndi-name="java:jboss/datasources/intfDS" pool-name="intf"enabled="true" use-ccm="false">

<xa-datasource-property name="URL">

        jdbc:oracle:thin:@127.0.0.1 :1521:orcl

</xa-datasource-property>

    <driver>oracle</driver>

    <xa-pool>

        <is-same-rm-override>false</is-same-rm-override>

        <interleaving>false</interleaving>

        <pad-xid>false</pad-xid>

        <wrap-xa-resource>true</wrap-xa-resource>

    </xa-pool>

    <security>

        <user-name>intf</user-name>

        <password>intf</password>

    </security>

    <validation>

        <validate-on-match>false</validate-on-match>

        <background-validation>false</background-validation>

           <background-validation-millis>0</background-validation-millis>

    </validation>

    <statement>

        <prepared-statement-cache-size>0</prepared-statement-cache-size>

        <share-prepared-statements>false</share-prepared-statements>

</statement>

</xa-datasource>

 

配置 2.2  oracle數據源-cx

<xa-datasource jndi-name="java:jboss/datasources/cxDS" pool-name="cx" enabled="true"use-ccm="false">

    <xa-datasource-property name="URL">

        jdbc:oracle:thin:@127.0.0.1 :1521:orcl

    </xa-datasource-property>

    <driver>oracle</driver>

    <xa-pool>

        <is-same-rm-override>false</is-same-rm-override>

        <interleaving>false</interleaving>

        <pad-xid>false</pad-xid>

        <wrap-xa-resource>true</wrap-xa-resource>

    </xa-pool>

    <security>

        <user-name>congxing</user-name>

        <password>congxing</password>

    </security>

    <recovery>

        <recover-credential>

            <user-name>congxing</user-name>

            <password>congxing</password>

        </recover-credential>

    </recovery>

    <validation>

        <validate-on-match>false</validate-on-match>

        <background-validation>false</background-validation>

        <background-validation-millis>0</background-validation-millis>

    </validation>

    <statement>

        <prepared-statement-cache-size>0</prepared-statement-cache-size>

        <share-prepared-statements>false</share-prepared-statements>

    </statement>

</xa-datasource>

 

三、配置JPA-persistence.xml

配置兩個persistence-unit,分別使用上面的數據源

 

配置 1.3.1   intf持久化單元

<persistence-unit name="intf" transaction-type="JTA">

   <jta-data-source>java:jboss/datasources/intfDS</jta-data-source>

</persistence-unit>

 

配置 1.3.2  cx持久化單元

<persistence-unit name="cx" transaction-type="JTA">

   <jta-data-source>java:jboss/datasources/cxDS</jta-data-source>

</persistence-unit>

 

四、配置EntityManagerFactory

使用spring自動注入entitymanger(若是用EJB的話有容器注入),因爲有兩個數據源,定義兩個EM

 

配置 1.4.1   intf EntityManagerFactory

<bean id="emf_intf"class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">

    <property name="persistenceUnitName" value="intf"/>

</bean>

 

 

 

配置 1.4.1   cx EntityManagerFactory

<bean id="emf_cx" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">

    <property name="persistenceUnitName" value="cx"/>

</bean>

 

五、配置JTA事務管理器

配置JTA事務管理器,並自動注入到業務層

 

配置 1.5.1   JTA事務管理器

<!-- 事務管理器配置-->

<bean id="transactionManager"class="org.springframework.transaction.jta.JtaTransactionManager" />

 

配置 1.5.2   事務傳播級別設置

<!-- aop事務屬性設置-->

<aop:config>

    <aop:advisor pointcut="execution(* com.rbc.lcp..*.service.*Impl.*(..))" advice-ref="txAdvice"/>

</aop:config>

   <tx:advice id="txAdvice">

    <tx:attributes>

       <tx:method name="*" propagation="REQUIRED" rollback-for="Exception,RuntimeException" />

    </tx:attributes>

</tx:advice>

 

配置 1.5.3   事務自動注入設置

<!-- 使用annotation注入事務 -->

<tx:annotation-driven transaction-manager="transactionManager" />

 

六、配置Spring Data JPA

定義項目中各模塊使用哪一個數據源,將EM注入到對應的模塊中。

 

配置 1.6.1   模塊1使用數據庫源1(intf)

<jpa:repositories base-package="com.rbc.lcp.manager.**.repository"

   entity-manager-factory-ref="emf_intf"

   transaction-manager-ref="transactionManager"

   />

 

配置 1.6.2   模塊2使用數據庫源2(cx)

<jpa:repositories base-package="com.rbc.lcp.manager2.**.repository"

   entity-manager-factory-ref="emf_cx"

   transaction-manager-ref="transactionManager"

   />

 

2、Atomikos實現JTA

使用atomikos就不需求依賴容器,這樣可使用tomcat,方便平常開發測試,和wildfly配置上大同小異,主要是數據源和事務管理器上差異較大。

因爲項目使用的是hibernate4,因此須要atomikos4的支持,網上的教程都是atomikos3+hibernate3,寫本文時atomikos4只是測試版,還沒發佈正式穩定版,資料不多,因此也花了很多時間才配置成功。

一、安裝atomikos

配置 2.1.1   在工程pom.xml中引入atomikos依賴

<dependency>

   <groupId>com.atomikos</groupId>

   <artifactId>atomikos-util</artifactId>

   <version>4.0.0M4</version>

</dependency>

<dependency>

   <groupId>com.atomikos</groupId>

   <artifactId>transactions-api</artifactId>

   <version>4.0.0M4</version>

</dependency>

<dependency>

   <groupId>com.atomikos</groupId>

   <artifactId>transactions-jta</artifactId>

   <version>4.0.0M4</version>

</dependency>

<dependency>

   <groupId>com.atomikos</groupId>

   <artifactId>transactions</artifactId>

   <version>4.0.0M4</version>

</dependency>

<dependency>

   <groupId>com.atomikos</groupId>

   <artifactId>transactions-jdbc</artifactId>

   <version>4.0.0M4</version>

</dependency>

<dependency>

   <groupId>com.atomikos</groupId>

   <artifactId>transactions-hibernate4</artifactId>

   <version>4.0.0M4</version>

</dependency>

 

 

 

二、配置XA數據源

配置 2.2.1   配置數據源

<!-- 兩個數據源的通用配置,方便下面直接引用 -->

<bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"

    init-method="init" destroy-method="close" abstract="true"  depends-on="txService">

    <property name="minPoolSize" value="10" />

    <property name="maxPoolSize" value="30" />

</bean>

 

<!-- 配置第一個數據源 -->

<bean id="intf_ds" parent="abstractXADataSource">

    <!-- value只要各個數據源不一樣就行,隨便取名 -->

    <property name="uniqueResourceName" value="oracle/intf" />

    <property name="xaDataSourceClassName"

        value="oracle.jdbc.xa.client.OracleXADataSource" />

    <property name="xaProperties">

        <props>

            <prop key="URL">jdbc:oracle:thin:@127.0.0.1 :1521:orcl</prop>

            <prop key="user">intf</prop>

            <prop key="password">intf</prop>

        </props>

    </property>

</bean>

 

<!-- 配置第二個數據源 -->

<bean id="cx_ds" parent="abstractXADataSource">

    <!-- value只要各個數據源不一樣就行,隨便取名 -->

    <property name="uniqueResourceName" value="oracle/cx" />

    <property name="xaDataSourceClassName"

        value="oracle.jdbc.xa.client.OracleXADataSource" />

    <property name="xaProperties">

        <props>

            <prop key="URL">jdbc:oracle:thin:@127.0.0.1 :1521:orcl</prop>

            <prop key="user">congxing</prop>

            <prop key="password">congxing</prop>

        </props>

    </property>

</bean>

 

三、配置JPA-persistence.xml

配置JPA持久化單元,注意和wildfly的區別,這裏並不須要指定數據源。

 

配置 2.3.1   intf持久化單元

<persistence-unit name="intf" transaction-type="JTA">

</persistence-unit>

 

配置 2.3.2  cx持久化單元

<persistence-unit name="cx" transaction-type="JTA">

</persistence-unit>

 

四、配置EntityManagerFactory

注意和wildfly的區別,數據源也在這裏配置

 

配置 2.4.1   intf EntityManagerFactory

<bean id="emf_intf"

    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

    <property name="jtaDataSource" ref="intf_ds" />

    <property name="persistenceUnitName" value="intf" />

    <property name="jpaVendorAdapter">

       <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">

           <property name="databasePlatform"

value="org.hibernate.dialect.Oracle10gDialect" />

       </bean>

    </property>

    <property name="jpaPropertyMap">

       <props>

           <prop key="hibernate.current_session_context_class">jta</prop>

           <prop key="javax.persistence.transactionType">jta</prop>

           <prop key="hibernate.transaction.jta.platform">

           com.atomikos.icatch.jta.hibernate4.AtomikosPlatform

           </prop>

           <prop key="hibernate.search.autoregister_listeners">false</prop>

       </props>

    </property>

</bean>

 

配置 2.4.1   cx EntityManagerFactory

<bean id="emf_cx"

    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

    <property name="jtaDataSource" ref="cx_ds" />

    <property name="persistenceUnitName" value="cx" />

    <property name="jpaVendorAdapter">

       <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">

           <property name="databasePlatform"

              value="org.hibernate.dialect.Oracle10gDialect" />

       </bean>

    </property>

    <property name="jpaPropertyMap">

       <props>

           <prop key="hibernate.current_session_context_class">jta</prop>

           <prop key="javax.persistence.transactionType">jta</prop>

           <prop key="hibernate.transaction.jta.platform">

           com.atomikos.icatch.jta.hibernate4.AtomikosPlatform

           </prop>

           <prop key="hibernate.search.autoregister_listeners">false</prop>

       </props>

    </property>

</bean>

 

五、配置JTA事務管理器

配置 2.5.1   JTA事務管理器

<bean id="txService" class="com.atomikos.icatch.config.UserTransactionServiceImp"

    init-method="init" destroy-method="shutdownWait">

</bean>

 

<bean id="txManager" class="com.atomikos.icatch.jta.UserTransactionManager"

    depends-on="txService" />

 

<bean id="userTx" class="com.atomikos.icatch.jta.UserTransactionImp"

    depends-on="txService" />

 

<bean id="transactionManager"

    class="org.springframework.transaction.jta.JtaTransactionManager">

    <property name="userTransaction" ref="userTx"></property>

    <property name="transactionManager" ref="txManager"></property>

</bean>

 

配置 2.5.2   事務傳播級別設置

<!-- aop事務屬性設置-->

<aop:config>

    <aop:advisor pointcut="execution(* com.rbc.lcp..*.service.*Impl.*(..))" advice-ref="txAdvice"/>

</aop:config>

   <tx:advice id="txAdvice">

    <tx:attributes>

       <tx:method name="*" propagation="REQUIRED" rollback-for="Exception,RuntimeException" />

    </tx:attributes>

</tx:advice>

 

配置 2S.5.3   事務自動注入設置

<!-- 使用annotation注入事務 -->

<tx:annotation-driven transaction-manager="transactionManager" />

 

六、配置Spring Data JPA

和前面wildfly同樣的,就不貼了。

相關文章
相關標籤/搜索