欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Atomikos实现分布式事务开发小结

程序员文章站 2022-05-23 12:27:41
...

由于项目中用到了操作多个数据库,并且要在通过Service方法里面完成,为了保证事务同步,引用了Atomikos,可参考http://www.atomikos.com/Documentation/。

 

1、加入Atomikos的相关类库,Maven项目中配置如下:  

 

<dependency>
	<groupId>com.atomikos</groupId>
	<artifactId>transactions-jdbc</artifactId>
	<version>3.7.0</version>
</dependency>

 

2、配置数据源,使用atomikos自带的datasource实现类,如AtomikosNonXADataSourceBean,AtomikosDataSourceBean等,经测试AtomikosDataSourceBean这类对数据库的要求挺多的,特别是Oracle,于是采用AtomikosNonXADataSourceBean。我配置了一个MySQL数据源,一个Oracle数据源如下:

 

<bean id="mysqlDS" class="com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean" init-method="init"
		destroy-method="close" p:uniqueResourceName="mysql_ds" p:testQuery="select 1 ">
		<property name="driverClassName" value="${mysql.connection.driverClass}" />
		<property name="url" value="${mysql.connection.url}" />
		<property name="user" value="${mysql.connection.username}" />
		<property name="password" value="${mysql.connection.password}" />
		<property name="poolSize" value="5" />
		<property name="maxPoolSize" value="30" />
	</bean>
	
	<bean id="oracleDS" class="com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean" init-method="init"
		destroy-method="close" p:uniqueResourceName="oracle_ds" p:testQuery="select 1 from dual ">
		<property name="driverClassName" value="${oracle.connection.driverClass}" />
		<property name="url" value="${oracle.connection.url}" />
		<property name="user" value="${oracle.connection.username}" />
		<property name="password" value="${oracle.connection.password}" />
		<property name="poolSize" value="5" />
		<property name="maxPoolSize" value="30" />
	</bean>

 

3、配置SessionFacotry ,不同的数据源对应不同的SessionFacotry.

	<bean id="mySqlSessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">

		<property name="dataSource" ref="mysqlDS" />
		<property name="packagesToScan">
			<list>
				<value>com.lyl.**.entity</value>
			</list>
		</property>
		<property name="entityInterceptor">
			<bean class="com.lyl.base.BaseDaoInterceptor"></bean>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">${mysql.dialect}</prop>
				<prop key="hibernate.hbm2ddl.auto">${mysql.hbm2ddl.auto}</prop>
				<prop key="hibernate.jdbc.fetch_size">50</prop>
				<prop key="hibernate.jdbc.batch_size">20</prop>
				<prop key="hibernate.query.factory_class">org.hibernate.hql.ast.ASTQueryTranslatorFactory
				</prop>
				<prop key="hibernate.jdbc.use_scrollable_resultset">false</prop>
				<prop key="hibernate.use_outer_join">true</prop>
				<prop key="hibernate.show_sql">false</prop>
				<prop key="hibernate.format_sql">true</prop>
				<prop key="hibernate.cache.use_query_cache">true</prop>
				<prop key="hibernate.cache.provider_class">
					org.hibernate.cache.EhCacheProvider
				</prop>
			</props>
		</property>
	</bean>

	<bean id="oracleSessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">

		<property name="dataSource" ref="oracleDS" />
		<property name="packagesToScan">
			<list>
				<value>com.lyl.**.entity</value>
			</list>
		</property>
		<property name="entityInterceptor">
			<bean class="com.lyl.base.BaseDaoInterceptor"></bean>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">${oracle.dialect}</prop>
				<prop key="hibernate.hbm2ddl.auto">${oracle.hbm2ddl.auto}</prop>
				<prop key="hibernate.jdbc.fetch_size">50</prop>
				<prop key="hibernate.jdbc.batch_size">20</prop>
				<prop key="hibernate.query.factory_class">org.hibernate.hql.ast.ASTQueryTranslatorFactory
				</prop>
				<prop key="hibernate.jdbc.use_scrollable_resultset">false</prop>
				<prop key="hibernate.use_outer_join">true</prop>
				<prop key="hibernate.show_sql">false</prop>
				<prop key="hibernate.format_sql">true</prop>
				<prop key="hibernate.cache.use_query_cache">true</prop>
				<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
				<prop key="hibernate.cache.provider_class">
					org.hibernate.cache.EhCacheProvider
				</prop>
			</props>
		</property>
	</bean>

 

4、配置事务管理。

根据需要配置了两个数据库事务,一个管理单个数据库操作,另一个管理多个数据库操作,配置不同的切面,针对不同的类,采取不同的事务方式。

 

	<bean id="baseTransactionManager"
		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory" ref="mySqlSessionFactory" />
	</bean>
	
	
	<tx:advice id="baseTxAdvice" transaction-manager="baseTransactionManager">
		<tx:attributes>
			<tx:method name="get*" read-only="true" />
			<tx:method name="query*" read-only="true" />
			<tx:method name="find*" read-only="true" />
			<tx:method name="load*" read-only="true" />
			<tx:method name="*" propagation="REQUIRED" />
		</tx:attributes>
	</tx:advice>

	<aop:config proxy-target-class="true">
		<aop:advisor pointcut="execution(* com.lyl..*Service.*(..))"
			advice-ref="baseTxAdvice" />
	</aop:config>

 

  

<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
		init-method="init" destroy-method="close">
		<property name="forceShutdown" value="true" />
	</bean>

	<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
		<property name="transactionTimeout" value="300" />
	</bean>

	<!-- JTA事务管理器 -->
	<bean id="jtaTransactionManager"
		class="org.springframework.transaction.jta.JtaTransactionManager">
		<property name="transactionManager" ref="atomikosTransactionManager" />
		<property name="userTransaction" ref="atomikosUserTransaction" />
	</bean>

	
	<tx:advice id="jtaTxAdvice" transaction-manager="jtaTransactionManager">
		<tx:attributes>
			<tx:method name="get*" read-only="true" />
			<tx:method name="query*" read-only="true" />
			<tx:method name="find*" read-only="true" />
			<tx:method name="load*" read-only="true" />
			<tx:method name="*" propagation="REQUIRED" />
		</tx:attributes>
	</tx:advice>

	<aop:config proxy-target-class="true">
		<aop:advisor pointcut="execution(* com.lyl..*Biz.*(..))"
			advice-ref="jtaTxAdvice" />
	</aop:config>

 

  5、配置两个操作不同数据库DAO类。

 

 

 

<bean id="mySqlHibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
		<constructor-arg name="sessionFactory">
			<ref bean="mySqlSessionFactory" />
		</constructor-arg>
	</bean>

	<bean id="oracleHibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
		<constructor-arg name="sessionFactory">
			<ref bean="oracleSessionFactory" />
		</constructor-arg>
	</bean>

	<bean id="mySqlBaseDao" class="com.lyl.base.BaseDao">
		<property name="hibernateTemplate" ref="mySqlHibernateTemplate"></property>
	</bean>

	<bean id="oracleBaseDao" class="com.lyl.base.BaseDao">
		<property name="hibernateTemplate" ref="oracleHibernateTemplate"></property>
	</bean>

 

 

6、需要执行分布式事务的Service类。

 

@Service
public class AccountBiz {
	
	@Resource
	private BaseDao mySqlBaseDao;
	
	@Resource
	private BaseDao oracleBaseDao;

	public void transer(Double amount) {
		Account_A a=new  Account_A();
		a.setAid(1L);
		Account_A aa=(Account_A)mySqlBaseDao.findById(a);
		Account_B b=new  Account_B();
		b.setBid(1L);
		Account_B bb=(Account_B)oracleBaseDao.findById(b);
		//bb.setIdNo("88888888");
		Date date=new Date();
		aa.setOpDate(date);
		aa.setAmount(aa.getAmount()+amount);
		bb.setOpDate(date);
		bb.setAmount(bb.getAmount()-amount);
		
		mySqlBaseDao.update(aa);
		oracleBaseDao.update(bb);
	}
	
	
}