`

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的...

    struts + spring + hibernate + velocity + ajax + jotm + acegi

    Struts、Spring、Hibernate、Velocity、Ajax、JOTM 和 Acegi 是一组常见的技术栈,它们在构建企业级Java Web应用程序时发挥着关键作用。这些技术各有专长,结合使用可以构建出高效、灵活且安全的系统。接下来,我们...

    spring+hibernate+jtom demo

    在本文中,我们将深入探讨如何使用Spring、Hibernate和JOTM进行分布式事务管理,以实现在一个Service方法中同时操作两个不同数据源的数据,并确保任何错误都能导致所有操作回滚。首先,我们需要了解这些技术的基本...

    spring+jotm 多数据源事务管理(二)hibernate

    JOTM是Java平台上的一个开放源代码事务管理器,它遵循JTA(Java Transaction API)标准,用于处理分布式事务。在Spring中集成JOTM可以提供更高级别的事务控制,确保在多数据源环境下事务的一致性和完整性。 首先,...

    spring-hibernate-jotm 例子

    为了运行这个示例,你需要将这些jar包添加到你的项目类路径中,然后配置Spring的事务管理器为JOTM,并配置Hibernate的相关设置。在Spring的配置文件中,你需要定义一个PlatformTransactionManager bean,通常是...

    Spring多数据源配置_分布式数据

    该系统的架构主要包括:Tomcat作为应用服务器,Spring用于业务逻辑层的控制,Hibernate作为ORM(对象关系映射)框架,JOTM(Java Open Transaction Manager)提供事务管理功能,Struts作为MVC(Model-View-...

    跨多个数据库操作,同时连接两个一上的数据库,用事物关联起来

    JTA是Java平台上的标准,用于管理分布式事务,它允许"同时连接两个或以上的数据库"。 JTA提供了统一的API,使得开发者可以在不同的事务资源(如数据库、消息队列等)之间进行协调。在Java环境中,Spring框架是实现...

    spring对多个数据库进行事务管理.doc

    对于多个数据库的事务管理,Spring主要依赖于JTA(Java Transaction API)和XAResource接口来实现分布式事务。然而,JTA的XA事务通常在J2EE环境下工作,需要容器支持,比如JBoss、WebLogic等。在J2SE环境中,Spring...

    java之hibernate和spring技术难点及其要点总结

    3. **分布式事务(jotm)**:当涉及到多个服务或数据库时,分布式事务成为必需,Spring支持与JOTM集成来实现这一目标。 4. **适配器模式与代理模式**:这两种设计模式在Spring中被广泛应用于实现AOP等功能。 5. **...

    跨多个数据库操作,同时连接多个的数据库,同时操作

    这通常涉及到跨数据库操作和分布式事务处理,确保数据的一致性和完整性。以下是一些关于这个主题的重要知识点: 1. **JTA(Java Transaction API)**:JTA是Java平台中用于处理分布式事务的标准API。它允许应用程序...

    简易搭建ssh 框架

    - **jotm.jar**:这是一个开源的JTA(Java Transaction API)实现,用于处理分布式事务。 - **ezmorph-1.0.4.jar**:这个库可能用于对象转换,帮助在不同数据格式间进行转换。 在搭建SSH框架时,通常需要以下步骤:...

    JBPM5入门学习.doc

    - **4.3.4 使用jotm配置tomcat数据源以支持JTA**: 通过Jotm配置Tomcat的数据源,以支持分布式事务。 - **4.3.5 Jbpm相关配置文件更新**: 更新JBPM相关的配置文件,如persistence.xml、jbpm.cfg.xml等。 - **4.3.6 ...

    OpenJWeb1.6Java快速开发平台功能手册090315

    - **3.4 JTA 集成**:集成 JOTM 的 JTA 产品,支持分布式事务处理。 - **3.5 日志拦截器**:采用 AOP 方式实现的日志拦截器,便于跟踪系统的运行情况。 - **3.6 字段校验器**:支持字段级别的数据校验,提高数据的...

    java开源包1

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

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

    Java数组倒置 简单 Java图片加水印,支持旋转和透明度设置 摘要:Java源码,文件操作,图片水印 util实现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...

Global site tag (gtag.js) - Google Analytics