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

由于项目中用到了操作多个数据库,并且要在通过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);
	}
	
	
}

猜你喜欢

转载自liuyunlong1229.iteye.com/blog/2255556