最近一直在研究怎么实现分布式事务,花了不少时间,测试工程启停测试了无数次,最终实现的时候其实也就是写一些配置文件,对于工程代码没什么影响。目前研究还不是很深入,对于全面崩溃恢复如何实现和测试还不清楚。本文先介绍基础的实现。
?
当业务需要在一个事务中操作多个不同的资源,例如多个数据库,消息队列,缓存等,那么就需要使用分布式事务了。在java中一般建议使用JTA,这样开发人员就不用关心什么叫XA协议,什么是两阶段提交协议。要使用JTA需要容器的支持,例如使用JBOSS,WebSphere;或者使用第三方组件例如JOTM、Atomikos。
?
JBOSS AS现在改名叫Wildfly了,以便和JBOSS EAP区分,后文我也改叫Wildfly。JOTM看起来是个死项目,我不打算使用。
?
由于目前开发框架基于Spring+JPA设计,所以本文的配置主要是在spring中。其实用EJB的话配置更简单,但需要容器支持。
?
a)???????? 首先按照以下路径新增目录:
wildfly-9.0.0.CR1\modules\system\layers\base\com\oracle\ojdbc14\main
b)???????? 把驱动文件ojdbc14.jar复制到此目录下
c)???????? 在main目录下新增配置文件module.xml
mudule.xml
<?xml version="1.0" encoding="UTF-8"?> <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> |
?
打开wildfly的standalone.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的数据源,暂时都是数据库,以后学会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> |
?
配置两个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> |
?
使用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事务管理器,并自动注入到业务层
?
<!-- 事务管理器配置--> <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" /> |
?
定义项目中各模块使用哪个数据源,将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" ?? /> |
?
使用atomikos就不需求依赖容器,这样可以使用tomcat,方便日常开发测试,和wildfly配置上大同小异,主要是数据源和事务管理器上差别较大。
由于项目使用的是hibernate4,所以需要atomikos4的支持,网上的教程都是atomikos3+hibernate3,写本文时atomikos4只是测试版,还没发布正式稳定版,资料很少,所以也花了不少时间才配置成功。
配置 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> |
?
?
?
配置 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持久化单元,注意和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> |
?
注意和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> |
?
配置 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" /> |
?
和前面wildfly一样的,就不贴了。
?
?
参考资料:
http://www.ibm.com/developerworks/cn/java/j-lo-jta/
http://blog.trixi.cz/2011/11/jta-transaction-manager-atomikos-or-bitronix/
https://wiki.kuali.org/display/KULRICE/Replacing+JOTM+and+XAPool+with+Atomikos
?
?
原文:http://hzy0769.iteye.com/blog/2294249