- 这里的项目是基于 Spring4.X + hibernate4.X架构的。最近的一个项目需要两个数据库,一个Oracle,一个是Sqlserver。业务中有一些需求需要跨库事务的一致,举个例子:合同签订保存到基于Oracle的ERP数据库,紧接着下发到Sqlserver的WMS数据库。
- 以前听说过JTA分布式事务,google到两种分布式框架:JOTM,atomikos。貌似JOTM简便点,就它了。
- 这种方式需要的jar包,首先在JOTM官网下面所有的jar包文件(文末提供下载),下图中选中的jar文件都是需要导入的
首先配置DataSource和SessionFactory
<!-- 数据库连接池 --> <bean id="dataSource1" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"> <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.1.200:1521:orcl" /> </bean> </property> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <bean id="dataSource2" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" > <property name="dataSource"> <bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown"> <property name="transactionManager" ref="jotm" /> <property name="driverName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" /> <property name="url" value="jdbc:sqlserver://192.168.1.200:1433;DatabaseName=middle_db" /> </bean> </property> <property name="user" value="${jdbc2.username}" /> <property name="password" value="${jdbc2.password}" /> </bean> <bean id="sessionFactory1" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource1" /> <property name="packagesToScan"> <list> <value>com.sy.domain</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.OracleDialect </prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.autoReconnect">true</prop> <!-- <prop key="hibernate.hbm2ddl.auto">update</prop> --> </props> </property> </bean> <bean id="sessionFactory2" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource2" /> <property name="packagesToScan"> <list> <value>com.sy.domain</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.SQLServerDialect </prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.autoReconnect">true</prop> <!-- <prop key="hibernate.hbm2ddl.auto">update</prop> --> </props> </property> </bean> <!-- erp.dao --> <bean id="commonDao" class="com.sy.dao.impl.CommonDaoImpl" > <property name="sessionFactory" ref="sessionFactory1"/> </bean> <!-- wms.dao --> <bean id="commonDao2" class="com.sy.dao.impl.CommonDaoImpl" > <property name="sessionFactory" ref="sessionFactory2"/> </bean>
因为我们要操作两个数据库,所以配置两个datasource,两个sessionfactory。需要注意的是我们这里是JOTM和xapool实现的分布式事务。JOTM实现了TransactionManager的功能,xapool通过使用非XA数据库驱动实现了XA数据库驱动的效果,具体这个以后再写文章。这里连接池的配置按照上面的文档配置即可。
这里DAO层因为两个数据库所以配置了两个。在Service层可以选择一起注入或者单个注入。
下面配置事务
<bean id="jotm" class="com.sy.utils.JotmFactoryBean"/> <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="userTransaction" ref="jotm" /> </bean> <tx:advice id="txAdvice" transaction-manager="jtaTransactionManager"> <tx:attributes> <!-- 传播行为 --> <tx:method name="save*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="insert*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="add*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="create*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="delete*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="update*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> <tx:method name="select*" propagation="SUPPORTS" read-only="true" /> <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> </tx:attributes> </tx:advice> <!-- 切面 --> <aop:config expose-proxy="true"> <aop:pointcut id="bussinessService" expression="execution(* com.sy.service.*.*(..))" /> <aop:advisor pointcut-ref="bussinessService" advice-ref="txAdvice"/> </aop:config> <tx:annotation-driven transaction-manager="jtaTransactionManager"/>
com.sy.utils.JotmFactoryBean需要手动实现,因为spring4.x不在提供JtaTransactionManager 的默认实现。
到这里JTA分布式事务的配置已经完成,下面我们看看Service层,和junit测试
@Service public class CommonServiceImpl implements CommonService{ /** serialVersionUID*/ private static final long serialVersionUID = -5991777455696969065L; @Resource private CommonDao commonDao; @Resource private CommonDao commonDao2; //测试两个数据库的事务 @Override public void saveTest() throws MyException { commonDao.update("update Dictionary set name=? where id=? ", new Value().add("货主类型").add(1l).getParams()); commonDao2.update("delete Member where id>25"); int i = 1/0; //这里异常,前面配置正确的话事务会回滚 } }
因为这是一个公共的Service层,需要操作两个数据库,所以两个DAO一起注入。下面是Junit测试代码
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:spring/applicationContext-*.xml"}) public class TestSupport extends AbstractJUnit4SpringContextTests { @Autowired private CommonService commonService; @Test public void save() throws MyException{ commonService.saveTest(); } public CommonService getCommonService() { return commonService; } public void setCommonService(CommonService commonService) { this.commonService = commonService; } }
运行结果如我们所料,事务回滚,OK!
下面是直接配置的方式,这种方式是一个老同事那边看到的。当时惊呼不用jta也能实现跨库事务啊。跟普通的单数据库项目配置一样,只是DataSource,SessionFactory,transactionmanager等都是两个。下面是配置
<!-- 数据库连接池 --> <bean id="dataSource1" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="driverClassName" value="${jdbc.driver}" /> <property name="maxActive" value="${jdbc.maxActive}" /> <property name="minIdle" value="${jdbc.minIdle}" /> </bean> <bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${jdbc2.url}" /> <property name="username" value="${jdbc2.username}" /> <property name="password" value="${jdbc2.password}" /> <property name="driverClassName" value="${jdbc2.driver}" /> <property name="maxActive" value="${jdbc2.maxActive}" /> <property name="minIdle" value="${jdbc2.minIdle}" /> </bean> <bean id="sessionFactory1" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource1" /> <property name="packagesToScan"> <list> <value>com.sy.domain</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.OracleDialect </prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.autoReconnect">true</prop> <!-- <prop key="hibernate.hbm2ddl.auto">update</prop> --> </props> </property> </bean> <bean id="sessionFactory2" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource2" /> <property name="packagesToScan"> <list> <value>com.sy.domain</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.SQLServerDialect </prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.autoReconnect">true</prop> <!-- <prop key="hibernate.hbm2ddl.auto">update</prop> --> </props> </property> </bean> <bean id="commonDao" class="com.sy.dao.impl.CommonDaoImpl" > <property name="sessionFactory" ref="sessionFactory1"/> </bean> <bean id="commonDao2" class="com.sy.dao.impl.CommonDaoImpl" > <property name="sessionFactory" ref="sessionFactory2"/> </bean> <bean id="transactionManager1" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory1" /> </bean> <bean id="transactionManager2" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory2" /> </bean> <tx:advice id="txAdvice1" transaction-manager="transactionManager1"> <tx:attributes> <!-- 传播行为 --> <tx:method name="save*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="insert*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="add*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="create*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="delete*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="update*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> <tx:method name="select*" propagation="SUPPORTS" read-only="true" /> <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> </tx:attributes> </tx:advice> <tx:advice id="txAdvice2" transaction-manager="transactionManager2"> <tx:attributes> <!-- 传播行为 --> <tx:method name="save*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="insert*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="add*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="create*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="delete*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="update*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> <tx:method name="select*" propagation="SUPPORTS" read-only="true" /> <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> </tx:attributes> </tx:advice> <!-- 切面 --> <aop:config expose-proxy="true"> <aop:pointcut id="bussinessService1" expression="execution(* com.sy.service.*.*(..))" /> <aop:advisor pointcut-ref="bussinessService1" advice-ref="txAdvice1"/> </aop:config> <aop:config expose-proxy="true"> <aop:pointcut id="bussinessService2" expression="execution(* com.sy.service.*.*(..))" /> <aop:advisor pointcut-ref="bussinessService2" advice-ref="txAdvice2"/> </aop:config>
这里配置和普通单库配置基本一样,连接池也是自由选择。但是都是两个配置,spring4对多个事务配置也是支持的。测试代码和上面JTA配置的一样,不再给出。
相关推荐
本篇文章将深入探讨如何在Spring中配置JTA事务管理,以实现跨数据库和资源的事务一致性。 首先,让我们了解JTA的基本概念。JTA是一个规范,它定义了接口和API,使得应用程序可以控制跨越多个数据存储(如数据库、...
在微服务架构中,跨服务的数据一致性是非常重要的,这就需要用到分布式事务。JTA是Java平台中处理分布式事务的标准API,它允许应用程序在一个全局事务中操作多个资源(如数据库、消息队列等)。Spring Boot支持JTA...
在企业级应用开发中,确保数据的一致性和完整性至关重要,这就需要用到事务管理。Spring框架提供了强大的事务管理功能,而分布式事务则是处理多数据库操作时的关键技术。本篇将详细讲解如何在Spring环境中结合Druid...
为了确保数据的一致性和完整性,通常会采用分布式事务来实现这一目标。Java Transaction API(JTA)就是用于支持这种分布式事务的标准API之一。 #### JTA简介 JTA是Java平台提供的一种标准接口,用于管理分布式的...
分布式事务是现代企业级应用中不可或缺的一部分,尤其是在大数据和微服务架构中,它确保了在多个数据库或资源管理系统中的数据一致性。本教程将深入探讨如何使用Spring框架、Java Transaction API (JTA) 和 Java ...
在Spring框架中,JTA事务管理主要用于处理分布式系统中的事务,确保数据的一致性和完整性。Spring提供了两种主要的方式来实现JTA事务管理:基于XML配置和基于注解的配置。通过这些方式,开发者可以声明式地控制事务...
编写测试类,利用Spring的`@Transactional`注解开启JTA事务,执行跨数据库的操作。测试类应确保在事务中进行所有操作,并在遇到错误时回滚事务。 ### 2. Spring引用Tomcat的JTA事务 #### 2.1. 添加所需JAR文件 在...
在IT行业中,分布式事务处理是大型系统中不可或缺的一部分,它确保了在多个数据库或资源管理器之间进行的数据一致性。Spring框架作为一个强大的企业级Java应用开发平台,提供了对事务管理的支持。而MyBatis作为轻量...
在Spring Boot应用中,整合JTA(Java Transaction API)实现多数据源事务管理是一个常见的需求,特别是在分布式系统中,为了确保数据的一致性和完整性。本文将深入探讨如何配置和使用Spring Boot与JTA来管理多个...
这是一项高级技术,它允许在多数据库环境或者微服务架构中进行一致性的数据操作。 首先,让我们了解什么是JTA。JTA是Java平台企业版(Java EE)的一部分,它为应用提供了统一的事务管理接口,支持跨多个数据源的...
本项目使用Spring Boot、Atomikos、JTA(Java Transaction API)、Hibernate和MySQL来实现分布式事务处理和多数据源管理,以确保在多个数据库操作之间保持事务的ACID特性。 首先,Spring Boot作为微服务开发的主流...
分布式事务在现代企业级应用中扮演着至关重要的角色,特别是在多服务、微服务架构中,确保数据的一致性和完整性是必不可少的。本话题主要聚焦于如何在Spring框架中结合Java Transaction API (JTA) 和 MyBatis 实现...
分布式事务是现代企业级应用中不可或缺的技术,尤其是在大数据和微服务架构中,保证数据的一致性和完整性至关重要。Spring 框架提供了强大的事务管理能力,而JTA(Java Transaction API)是Java平台上的标准分布式...
本项目“spring+jotm+ibatis+mysql实现JTA分布式事务”旨在利用这些技术来确保在分布式环境中的数据一致性。下面将详细介绍这个项目所涉及的知识点。 首先,Spring框架是Java开发中最常用的应用框架之一,它提供了...
通过JTA,我们可以实现分布式事务的一致性,即使在分布式环境中的多个组件发生故障,也能保证数据的一致性。 Spring框架作为Java领域广泛使用的轻量级框架,提供了对JTA的支持,使得开发者可以方便地在应用中集成和...
这篇博客"多数据源事务jta测试"可能探讨了如何在Java环境中利用JTA来实现对不同数据库的事务一致性。 JTA允许应用程序进行分布式事务处理,这意味着一个事务可以跨越多个数据库或者其他事务资源。这对于那些需要在...
JTA允许在分布式环境中协调多个资源的事务,确保所有操作要么全部完成,要么全部回滚,这就是ACID(原子性、一致性、隔离性和持久性)原则的体现。JTA通过UserTransaction接口和TransactionManager接口提供对事务的...
在分布式系统中,由于多个资源(如数据库、消息队列等)需要进行原子操作,因此需要一个事务管理器来协调这些操作,确保事务的ACID特性(原子性、一致性、隔离性和持久性)。Atomikos通过实现JTA规范,允许应用程序...
Spring框架提供了对JTA(Java Transaction API)的支持,允许开发者处理跨多个数据存储的事务一致性。本文将深入探讨如何在Tomcat应用服务器上集成JTA,并使用JOTM(Java Open Transaction Manager)或Atomikos作为...