使用Atomikos来进行分布式事务(XA)开发
结合Spring使用
和Spring集成的时候,不需要JNDI服务器注意,不支持Spring的事务传播性:PROPAGATION_NESTED
JTA事务管理器配置样例:
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34  | 
						<bean id="localLogAdministrator" class="com.atomikos.icatch.admin.imp.LocalLogAdministrator" /> <bean id="userTransactionService" class="com.atomikos.icatch.config.UserTransactionServiceImp" init-method="init"     destroy-method="shutdownForce">     <constructor-arg>         <!-- 配置Atomikos属性 -->         <props>             <prop key="com.atomikos.icatch.service">com.atomikos.icatch.standalone.UserTransactionServiceFactory</prop>         </props>     </constructor-arg>     <property name="initialLogAdministrators">         <list>             <ref bean="localLogAdministrator" />         </list>     </property> </bean> <!-- Atomikos 事务管理器配置 --> <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close"     depends-on="userTransactionService">     <property name="startupTransactionService" value="false" />     <!-- close()时是否强制终止事务 -->     <property name="forceShutdown" value="false" /> </bean> <!-- Atomikos UserTransaction配置 --> <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp" depends-on="userTransactionService">     <property name="transactionTimeout" value="300" /> </bean> <!-- JTA事务管理器 --> <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" depends-on="userTransactionService">     <property name="transactionManager" ref="atomikosTransactionManager" />     <property name="userTransaction" ref="atomikosUserTransaction" /> </bean>  | 
					
配合消息中间件使用(ActiveMQ)的配置样例:
3.9以前的版本,必须设置sessionTransacted为true
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21  | 
						<bean id="xaFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">     <property name="brokerURL" value="tcp://localhost:61616" /> </bean> <bean id="jmsFactory" class="com.atomikos.jms.AtomikosConnectionFactoryBean" init-method="init" destroy-method="close">     <property name="uniqueResourceName" value="amq" />     <property name="xaConnectionFactory" ref="xaFactory" /> </bean> <bean id="tipsMessageListener" class="cc.gmem.demo.TipsMessageListener" /> <!-- 接收消息 --> <jms:listener-container container-type="default" connection-factory="jmsFactory"     transaction-manager="jtaTransactionManager" session-transacted="true">     <jms:listener destination="TIPS.10000.BATCH" ref="tipsMessageListener" method="onMessage" /> </jms:listener-container> <!-- 发送消息 --> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">     <property name="connectionFactory">         <ref bean="jmsFactory" />     </property>     <property name="receiveTimeout" value="1000" />     <property name="sessionTransacted" value="true" /> </bean>  | 
					
配合数据库使用的配置样例:
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37  | 
						<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">     <!-- 必须为Hibernate指定一个Atomikos JTA/XA 数据源 -->     <property name="dataSource" ref="dataSource" /> </bean> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">     <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean id="dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">     <property name="uniqueResourceName" value="mysqlDataSource" />     <property name="xaDataSourceClassName">         <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>     </property>     <property name="xaProperties">         <props>             <prop key="databaseName">gmem</prop>             <prop key="serverName">localhost</prop>             <prop key="port">3306</prop>             <prop key="user">user</prop>             <prop key="password">pswd</prop>             <prop key="url">jdbc:mysql://localhost:3306/gmem</prop>         </props>     </property>     <property name="minPoolSize" value="10"> </bean> <bean id="dataSourceOracle" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">     <property name="uniqueResourceName" value="oralceDataSource" />     <property name="xaDataSourceClassName">         <value>oracle.jdbc.xa.client.OracleXADataSource</value>     </property>     <property name="xaProperties">         <props>             <prop key="user">gmemx</prop>             <prop key="password">pswd</prop>             <prop key="URL">jdbc:oracle:thin:@192.168.0.25:1521:DEV</prop>         </props>     </property> </bean>  | 
					
不使用Spring,单独和Hibernate集成
Hibernate配置示例:| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23  | 
						<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC         "-//Hibernate/Hibernate Configuration DTD 3.0//EN"         "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration>     <session-factory>         <property name="connection.datasource">ds0</property>         <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>         <property name="current_session_context_class">jta</property>         <property name="transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</property>          <property name="transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>         <property name="connection.release_mode">auto</property>         <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>         <property name="show_sql">true</property>         <mapping resource="cc/gmem/demo/vo/User.hbm.xml"/>     </session-factory> </hibernate-configuration>  | 
					
jndi.properties配置示例:
| 
					 1  | 
						java.naming.factory.initial=org.apache.naming.java.javaURLContextFactory  | 
					
jta.properties配置示例:
| 
					 1 2 3  | 
						com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory com.atomikos.icatch.automatic_resource_registration=true com.atomikos.icatch.console_log_level=DEBUG  | 
					
通过编程方式初始化数据源,并绑定到JNDI,进行编程式事务控制:
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45  | 
						import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.transaction.UserTransaction; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import com.atomikos.jdbc.SimpleDataSourceBean; Context ctx = new InitialContext(); SimpleDataSourceBean ds0 = new SimpleDataSourceBean(); ds0.setUniqueResourceName("ds0"); ds0.setXaDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"); ds0.setXaDataSourceProperties("databaseName=gmem"); ds0.setConnectionPoolSize(10); ctx.rebind("ds0", ds0); SimpleDataSourceBean ds1 = = new SimpleDataSourceBean(); ds0.setUniqueResourceName("ds1"); ds0.setXaDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"); ds0.setXaDataSourceProperties("databaseName=gmembkp"); ds0.setConnectionPoolSize(10); ctx.rebind("ds1", ds1); ctx.close(); UserTransaction tx = new com.atomikos.icatch.jta.UserTransactionImp(); SessionFactory sf0 = new Configuration().configure("/hibernate0.cfg.xml").buildSessionFactory(); SessionFactory sf1 = new Configuration().configure("/hibernate1.cfg.xml").buildSessionFactory(); tx.setTransactionTimeout(60); tx.begin(); try {     //执行DML操作     userTransaction.commit(); } catch (Exception ex) {     tx.rollback(); } sf0.close(); sf1.close(); ds0.close(); ds1.close();  | 
					
一些常见问题
com.atomikos.icatch.RollbackException: Prepare: NO vote
详细参考:http://www.atomikos.com/Documentation/JtaProperties
注意事务的超时设置:UserTransaction.setTransactionTimeout()
另外,超时设置无法超过最大值限制:jta.properties中的com.atomikos.icatch.max_timeout
Oracle 9.2.0.8.0版本下操作blob导致挂起(Halt)
10.x驱动无该问题,可能Oracle驱动的bug。INSERT时没有问题,UPDATE时,如果1个blob也没问题,2个就挂起。
可以禁用Hibernate批量操作来临时解决:jdbc.batch_size=0
            
Leave a Reply