`

Spring + Hibernate + JOTM 分布式事务配置

    博客分类:
  • SSH
 
阅读更多

多数据源情况下的事务管理,适用于部署到非应用服务器的Web应用和Standalone的应用程序

 

1. 环境

    Spring + Hibernate + JOTM, Oracle Database

 

2. 场景用例

    两个数据库分别存储User信息和Address信息

 

3. 代码及配置

 

    1) carol.properties

#JNDI调用协议

        carol.protocols=jrmp

        #不使用CAROL JNDI封装器

        carol.start.jndi=false

        #不启动命名服务器

        carol.start.ns=false

 

 

    2) 简单的DAO层实现

 

 

public class BaseDaoImpl<T> extends HibernateTemplate
 implements BaseDao<T> {
	private Class<T> type;
	
	public BaseDaoImpl(Class<T> type) {
		this.type = type;
	}

	@Override
	public void saveEntity(T entity) {
		this.saveOrUpdate(entity);
	}
}

 

 

    3) 业务实现类

 

 

 

public class BusinessServiceImpl 
implements BusinessService{
	private BaseDao<User> userDao;
	private BaseDao<Address> addressDao;

	@Override
	public void addUserAdressCombination(User user, Address address) {
		userDao.saveEntity(user);
		addressDao.saveEntity(address);
	}

	public BaseDao<User> getUserDao() {
		return userDao;
	}

	public void setUserDao(BaseDao<User> userDao) {
		this.userDao = userDao;
	}

	public BaseDao<Address> getAddressDao() {
		return addressDao;
	}

	public void setAddressDao(BaseDao<Address> addressDao) {
		this.addressDao = addressDao;
	}

}

 

    4) 简单的测试类

 

public class Main {

	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] {"spring.xml"});
		BusinessService bs = (BusinessService)ctx.getBean("businessService");
		User user = new User();
		user.setName("kevin");
		user.setPassword("kevin");
		Address address = new Address();
		address.setCity("Shanghai");
		//address.setStreet("Guo Shou Jing Road"); //Normal situation
		address.setStreet("Guo Shou Jing Road XXX Company"); // 字符串长度超过数据库中字段的长度
		bs.addUserAdressCombination(user, address);
	}
}

 

 

    5)Spring配置

 

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >

<beans>
	<!-- 1. JOTM本地实例 -->
	<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" />

	<!-- 2. JTA事务管理器 -->
	<bean id="txManager"
		class="org.springframework.transaction.jta.JtaTransactionManager">
		<!-- 2.1:指定userTransaction属性 -->
		<property name="userTransaction" ref="jotm" />
	</bean>

	<!-- 3. XAPool配置,内部包含了一个XA数据源,对应user数据库 -->
	<bean id="userDataSource" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"
		destroy-method="shutdown">
		<property name="dataSource">
			<!-- 3.1:内部XA数据源 -->
			<bean class="org.enhydra.jdbc.standard.StandardXADataSource"
				destroy-method="shutdown">
				<property name="transactionManager" ref="jotm" />
				<property name="driverName" value="oracle.jdbc.driver.OracleDriver" />
				<property name="url" value="jdbc:oracle:thin:@192.168.0.33:1521:XE" />
			</bean>
		</property>
		<property name="user" value="kevin" />
		<property name="password" value="kevin" />
	</bean>

	<!-- 4. 配置另一个XAPool,对应address数据库 -->
	<bean id="addressDataSource" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"
		destroy-method="shutdown">
		<property name="dataSource">
			<bean class="org.enhydra.jdbc.standard.StandardXADataSource"
				destroy-method="shutdown">
				<property name="transactionManager" ref="jotm" />
				<property name="driverName" value="oracle.jdbc.driver.OracleDriver" />
				<property name="url" value="jdbc:oracle:thin:@192.168.0.8:1521:XE" />
			</bean>
		</property>
		<property name="user" value="kevin" />
		<property name="password" value="kevin" />
	</bean>

	<!-- 5. 配置对应userDataSource数据源的userSessionFactory -->
	<bean id="userSessionFactory"
		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<property name="dataSource">
			<ref local="userDataSource" />
		</property>
		<property name="mappingDirectoryLocations">
			<list>
				<value>classpath:hbm</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.jdbc.batch_size">50</prop>
				<prop key="hibernate.cache.use_query_cache">true</prop>
				<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
			</props>
		</property>
		<!-- 5.1 这里不要配,否则会报Could not find UserTransaction in JNDI [java:comp/UserTransaction] 
		<property name="jtaTransactionManager">
			<ref bean="jotm" />
		</property> 
		-->
	</bean>
	
	<!-- 6. 配置对应addressDataSource数据源的addressSessionFactory -->
	<bean id="addressSessionFactory"
		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<property name="dataSource">
			<ref local="addressDataSource" />
		</property>
		<property name="mappingDirectoryLocations">
			<list>
				<value>classpath:hbm</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.jdbc.batch_size">50</prop>
				<prop key="hibernate.cache.use_query_cache">true</prop>
				<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
			</props>
		</property>
		<!-- 6.1 这里不要配,否则会报Could not find UserTransaction in JNDI [java:comp/UserTransaction] 
		<property name="jtaTransactionManager">
			<ref bean="jotm" />
		</property>
		 -->
	</bean>
	
	<!-- 7. 对应userSessionFactory数据源的userDao -->
	<bean id="userDao" class="com.kevin.jotm.dao.impl.BaseDaoImpl">
		<constructor-arg>
			<value>com.kevin.jotm.pojo.User</value>
		</constructor-arg>
		<property name="sessionFactory">
			<ref bean="userSessionFactory"/>
		</property>
	</bean>
	
	<!-- 8. 对应addressSessionFactory数据源的addressDao -->
	<bean id="addressDao" class="com.kevin.jotm.dao.impl.BaseDaoImpl">
		<constructor-arg>
			<value>com.kevin.jotm.pojo.Address</value>
		</constructor-arg>
		<property name="sessionFactory">
			<ref bean="addressSessionFactory"/>
		</property>
	</bean>
	
	
	<!-- 9. 进行跨数据库JTA事务的业务类 -->
	<bean id="businessService" class="com.kevin.jotm.service.impl.BusinessServiceImpl">
		<property name="userDao" ref="userDao" />
		<property name="addressDao" ref="addressDao" />
	</bean>
	
	<!-- 10. 事务拦截器 -->
	<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionManager" ref="txManager" />
        <property name="transactionAttributes">
            <props>    
                <prop key="*">-Exception</prop>
            </props>
        </property>
    </bean>
    
    <!-- 11. 事务增强器 -->
    <bean id="transactionAdvisor" class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
        <property name="transactionInterceptor" ref="transactionInterceptor" />
    </bean>
    
    <!-- 12. 自动代理 -->
    <bean id="beanproxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames">
            <value>*Service</value>
        </property>
        <property name="interceptorNames">
            <list>
                <value>transactionAdvisor</value>
            </list>
        </property>
    </bean>
	
</beans>

 

以上代码已经过测试可以实现分布式事务管理。 为了对比,曾试过使用BasicDataSource且不使用JOTM,使用org.springframework.orm.hibernate3.HibernateTransactionManager管理多数据源情况下的事务,开始时看到异常情况下也可以同时回滚,但是后来发现是Hibernate缓存造成的假象,原因是:默认情况下,Hibernate 要在事务提交时才将数据的更改同步到数据库中,而事务提交发生在业务方法返回前,如果有异常,方法没有正常返回,User信息没有被同步到数据库而不是被回滚掉。这时需要调用 flush() 方法将数据更改同步到数据库才能比较出两种情况下的不同。

分享到:
评论

相关推荐

    Spring+Jotm+Hibernate+Oracle+Junit 实现JTA分布式事务要求Demo工程

    2.Spring+Jotm整合实现JTA分布式事务,应用场景如转账等,同一事务内完成db1用户加100元、db2用户减100元。 3.Spring+Junit4单元测试,优点:不会破坏数据库现场,等等。 (特别注意:Spring3.0里不在提供对jotm的...

    JAVA上百实例源码以及开源项目

     util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码...

    JAVA上百实例源码以及开源项目源代码

     util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码...

    java开源包1

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包11

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包2

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包3

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包6

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包5

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包10

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包4

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包8

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包7

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包9

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    java开源包101

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

    Java资源包01

    Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java...

Global site tag (gtag.js) - Google Analytics