引言:
Spring 通过AOP技术可以让我们在脱离EJB的情况下享受声明式事务的丰盛大餐。
通过配合使用ObjectWeb的JOTM开源项目,在不需要Java EE应用服务器的情况下,Spring也可以提供JTA事务。
用框架的话只要配置好对个数据源,和工厂,公用一个JtaTransactionManager事物管理器(xa事物管理),一个事物中有多个不同数据库操作不同数据源(xa数据源)的时候会自动启用
两阶段提交,在加入事物标签的地方遇到任何异常就会自动回滚。
三种集成方式:
1. 直接集成JOTM提供JTA事务管理(无应用服务器支持,常用于单元测试)
2. 引用应用服务器(如Tomcat)的JNDI数据源,间接实现JTA事务管理
3. 使用特定于应用服务器的事务管理器,使用JTA事务的高级功能(Weblogic,Websphere)
(注意一) 以上方式配置大统小异,只是数据源配置不一样(专用的可用于分布式的数据源配置)xa数据源
1,用了JOTM配置方式
2,用了jndi数据源(见:博客:配置Tomcat JNDI数据源)
3,AtomikosDataSourceBean(类Spring常规)
4,还可以用常规的spring数据源但是要xa式的StandardXAPoolDataSource
(注意二)当然事物管理也要用xa的事务管理器:
由于大部分服务器获取jta的方式都不尽相同,spring还针对不同的服务器提供了不同的jta实现,例如:
WebLogicJtaTransactionManager
WebSphereUowTransactionManager
OC4JJtaTransactionManager
JtaTransactionManager--》tomcat
(注意三)ibatis与hibernate是一样的,只需要将hibernate的sessionFactory部分更换一下(数据源,事物管理器都一样)
1. JOTM直接集成
1.1. 将JOTM以下类库添加到类路径中:
jotm.jar
xapool.jar
jotm_jrmp_stubs.jar
jta-spec1_0_1.jar
connector-1_5.jar
1.2. 编写JOTM配置文件,放到类路径下
carol.properties
#JNDI调用协议
carol.protocols=jrmp
#不使用CAROL JNDI封装器
carol.start.jndi=false
#不启动命名服务器
carol.start.ns=false
1.3. 在MySQL上建立两个数据库
在MySQL数据库中运行SQL脚本,建立topicdb和postdb两个数据库,
在topicdb数据库中创建t_topic表,在postdb数据库中创建t_post表。
我们希望在这两个数据库上进行JTA事务。
1.4. 在Spring配置文件中配置JOTM,并实现具体业务类
代码清单 1 applicationContext-jta.xml
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" /> ①JOTM本地实例 ②JTA事务管理器 <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="userTransaction" ref="jotm" /> ②-1:指定userTransaction属性 </bean> ③XAPool配置,内部包含了一个XA数据源,对应topicdb数据库 <bean id="topicDS" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown"> <property name="dataSource"> ③-1:内部XA数据源 <bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown"> <property name="transactionManager" ref="jotm" /> <property name="driverName" value="com.MySQL.jdbc.Driver" /> <property name="url" value="jdbc:MySQL://localhost:3309/topicdb" /> </bean> </property> <property name="user" value="root" /> <property name="password" value="1234" /> </bean> ④按照③相似的方式配置另一个XAPool,对应postdb数据库, <bean id="postDS" 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="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3309/postdb" /> </bean> </property> <property name="user" value="root" /> <property name="password" value="1234" /> </bean> ⑤配置访问topicDB数据源的Spring JDBC模板 <bean id="topicTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="topicDS" /> </bean> ⑥配置访问postDB数据源的Spring JDBC模板 <bean id="postTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="postDS" /> </bean> ⑦基于topicTemplate数据源的topicDao <bean id="topicDao" class="com.baobaotao.dao.jdbc.TopicJdbcDao"> <property name="jdbcTemplate" ref="topicTemplate" /> </bean> ⑧基于postTemplate数据源的postDao <bean id="postDao" class="com.baobaotao.dao.jdbc.PostJdbcDao"> <property name="jdbcTemplate" ref="postTemplate" /> </bean> ⑨进行跨数据库JTA事务的业务类 <bean id="bbtForum" class="com.baobaotao.service.impl.BbtForumImpl"> <property name="topicDao" ref="topicDao" /> <property name="postDao" ref="postDao" /> </bean> ⑩对BbtForumImpl业务类中的@Transaction注解进行驱动 <tx:annotation-driven transaction-manager="txManager" />
代码清单 2 BbtForumImpl
package com.baobaotao.service.impl; import org.springframework.transaction.annotation.Transactional; import com.baobaotao.dao.PostDao; import com.baobaotao.dao.TopicDao; import com.baobaotao.domain.Forum; import com.baobaotao.domain.Topic; import com.baobaotao.service.BbtForum; @Transactional //①事务注解,以便Spring动态织入事务管理功能 public class BbtForumImpl implements BbtForum { private TopicDao topicDao; private PostDao postDao; public void addTopic(Topic topic) throws Exception { //②将方法将被施加JTA事务的增强 topicDao.addTopic(topic); postDao.addPost(topic.getPost()); } }
1.5. 在Spring中运行测试
package com.baobaotao.service; import org.springframework.test.AbstractDependencyInjectionSpringContextTests; … public class TestBbtForumJta extends AbstractDependencyInjectionSpringContextTests{ private BbtForum bbtForum; private final Logger logger = Logger.getLogger(getClass()); public void setBbtForum(BbtForum bbtForum) { this.bbtForum = bbtForum; } protected String[] getConfigLocations() { return new String[]{"classpath:applicationContext-jta.xml"}; } public void testAddPost() throws Exception{ logger.info("begin........"); Topic topic = new Topic(); topic.setTopicTitle("Title -pfb"); Post post = new Post(); post.setPostText("post content -pfb"); topic.setPost(post); bbtForum.addTopic(topic); //①使用了JTA事务的业务方法 logger.info("end........"); } }
2. Spring引用Tomcat的 JTA事务
Tomcat是Servlet容器,但它提供了JNDI的实现,
因此用户可以象在Java EE应用程序服务器中一样,在Tomcat中使用JNDI查找JDBC数据源。
在事务处理方面,Tomcat本身并不支持JTA,但是可以通过集成JOTM达到目的。
(测试环境:Tomcat 5.5+JOTM 2.3)
2.1. 添加所需的JAR文件
将JOTM以下类包添加到<Tomcat安装目录>/common/lib目录中:
jotm.jar
jotm_jrmp_stubs.jar
jotm_iiop_stubs.jar
ow_carol.jar
jta-spec1_0_1.jar
jts1_0.jar
objectweb-datasource.jar
xapool.jar
howl.jar
connector-1_5.jar
同时,还需要添加相应数据库的JDBC驱动类包,例如MySQL的mysql.jar。
2.2. 配置JOTM
新建一个carol.properties配置文件,放置到<Tomcat安装目录>/common/classes目录下,配置文件内容如下:
#JNDI调用协议
carol.protocols=jrmp
# 本地RMI调用
carol.jvm.rmi.local.call=true
# 不使用CAROL的JNDI封装器
carol.start.jndi=false
# 不启用命名服务器
carol.start.ns=false
# 命名工厂类
carol.jndi.java.naming.factory.url.pkgs=org.apache.naming
将carol.start.jndi设置为false,让JOTM不使用CAROL JNDI wrapper,从而可以避免类装载错误的发生。
2.3. 配置Tomcat环境,配置JNDI的数据源
在<Tomcat安装目录>/conf/context.xml文件中添加以下内容:
<!-- ①:JNDI数据源 --> <Resource name="jdbc/topicDS" auth="Container" type="javax.sql.DataSource" factory="org.objectweb.jndi.DataSourceFactory" username="root" password="1234" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3309/topicdb" maxActive="30" maxIdle="30" /> <!-- ①:JNDI数据源 --> <Resource name="jdbc/postDS" auth="Container" type="javax.sql.DataSource" factory="org.objectweb.jndi.DataSourceFactory" username="root" password="1234" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3309/postdb" maxActive="30" maxIdle="30" /> <!-- ②JOTM JTA事务管理 --> <Transaction factory="org.objectweb.jotm.UserTransactionFactory" jotm.timeout="60" />
4. Spring中相应的配置
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd"> <jee:jndi-lookup id="topicDS" jndi-name="java:comp/env/jdbc/topicDS" /> <jee:jndi-lookup id="postDS" jndi-name="java:comp/env/jdbc/postDS" /> <bean id="topicTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="topicDS" /> </bean> <bean id="postTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="postDS" /> </bean> <bean id="topicDao" class="com.baobaotao.dao.jdbc.TopicJdbcDao"> <property name="jdbcTemplate" ref="topicTemplate" /> </bean> <bean id="postDao" class="com.baobaotao.dao.jdbc.PostJdbcDao"> <property name="jdbcTemplate" ref="postTemplate" /> </bean> <bean id="bbtForum" class="com.baobaotao.service.impl.BbtForumImpl"> <property name="topicDao" ref="topicDao" /> <property name="postDao" ref="postDao" /> </bean> <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" /> <tx:annotation-driven transaction-manager="txManager" /> </beans>
3. 在特定应用服务器使用JTA
BEA WebLogic
在一个使用WebLogic 7.0、8.1或更高版本的环境中,你一般会优先选用特定于WebLogic的 WebLogicJtaTransactionManager 类
来取代基础的 JtaTransactionManager 类。
因为在WebLogic环境中,该类提供了对Spring事务定义的完全支持,超过了标准的JTA语义。
你可以使用以下的配置达到目的:
<bean id="txManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager"/>
它的特性包括:支持事务名,支持为每个事务定义隔离级别,以及在任何环境下正确地恢复事务的能力。
IBM WebSphere
在WebSphere 5.1、5.0和4.x环境下,你可以使用Spring的 WebSphereTransactionManagerFactoryBean 类。
这是一个工厂类,通过WebSphere的 静态访问方法(每个版本的WebSphere中都不同)获取到JTA TransactionManager 实例。
一旦通过工厂bean获取到JTA TransactionManager 实例,
就可以使用该实例装配一个Spring的 JtaTransactionManager bean,
它封装了JTA UserTransaction,提供增强的事务语义。
<bean id="wsJtaTm" class="org.springframework.transaction.jta.WebSphereTransactionManagerFactoryBean" /> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManager ref=" wsJtaTm " /> <!--①引用WebSphere的JTA事务管理器--> </bean>
名称解释:
JOTM(Java Open Transaction Manager)是ObjectWeb的一个开源JTA实现,
它本身也是开源应用程序服务器JOnAS(Java Open Application Server)的一部分,
为其提供JTA分布式事务的功能。
参考:
JTA事务管理(一)http://mavin.zhou.blog.163.com/blog/static/114522435200971822334475/
JTA事务管理(二)http://mavin.zhou.blog.163.com/blog/static/114522435200971822912342/
其它:
JTA集成JOTM或Atomikos配置分布式事务(Tomcat应用服务器) http://kb.cnblogs.com/a/2012014/
相关推荐
3. **两阶段提交(2PC)**:这是一种经典的分布式事务解决方案,包括准备阶段和提交阶段。所有参与者首先在准备阶段进行预提交,然后在提交阶段根据所有参与者的结果决定是否正式提交。然而,2PC存在单点故障、阻塞...
"浅谈分布式事务实现技术及应用场景探讨" 分布式事务是指在分布式系统中,多个节点之间的数据访问和更新操作集合,需要保证事务的原子性、一致性、隔离性和持久性。随着软件系统支持用户数的不断提高,对其架构的...
还有XA以及两阶段提交,并通过实例演示了使用JTA,通过两阶段提交,实现多数据源的事务实现。... 4-1 Spring事务机制_基本接口 4-2 Spring事务机制_实现 4-3 Jpa事务实例 4-4 Jms事务原理 4-5 Jms-session事务实例 4...
MySQL的XA实现允许应用程序通过两阶段提交(2PC)协议来确保分布式事务的一致性。 #### 七、两阶段提交(2PC) 两阶段提交是实现分布式事务的核心机制。其主要步骤如下: 1. **准备阶段(Prepare Phase)**:事务管理...
分布式事务的解决方案通常基于最终一致性,比如两阶段提交(2PC)和三阶段提交(3PC)协议。这些协议在处理分布式事务时,能够保证系统在面临网络分区或节点故障时仍然能按照预定的方式处理事务。 在分布式事务的控制...
一种是基于2PC(两阶段提交)的算法,它通过协调者协调各个参与者节点,在第一阶段准备操作,并在第二阶段提交或回滚,从而保证分布式系统的一致性。然而,这种方法牺牲了可用性,特别是在网络分区的情况下,系统...
具体来说,XA 协议通过两阶段提交(Two-Phase Commit, 2PC)实现这一点,其中包含准备(Prepare)和提交(Commit)阶段。 #### 2. MySQL XA 事务的特点 ##### 2.1 跨数据库实例支持 MySQL 的 XA 事务支持在不同的 ...
- **两阶段提交(Two-Phase Commit, 2PC)**:协调者和参与者两阶段交互,决定是否提交或回滚所有事务。这种方法简单但效率低,容易造成阻塞,并且在协调者失败时可能导致死锁。 - **三阶段提交(Three-Phase Commit, ...
在MySQL中实现分布式事务通常使用两阶段提交协议(2PC)。事务的第一阶段是准备阶段,所有参与者节点准备提交事务,并将事务状态锁定到一个预备状态。第二阶段是提交阶段,如果所有参与者都准备好了,事务管理器则...
3. **2PC(两阶段提交)协议**:这是最早的分布式事务处理协议,包括准备阶段和提交阶段。虽然简单,但存在阻塞、单点故障等问题。 4. **3PC(三阶段提交)协议**:为了解决2PC的问题,3PC引入了预提交阶段,降低了...
它维护全局事务的状态,并通过两阶段提交(2PC)协议确保事务的一致性。 2. **服务资源管理器 (Resource Manager, RM)**:每个参与分布式事务的服务都需要实现RM接口,用于管理本地事务,与GTC进行通信,报告本地...
此外,JTA还支持两阶段提交(2PC)协议,以协调不同资源的提交过程,确保全局一致性。 总之,JTA分布式事务的示例代码展示了如何在Java环境中处理跨多个数据源的事务,保证在分布式系统中的数据一致性。理解和掌握...
每个操作都是本地事务,这样可以避免传统两阶段提交(2PC)带来的性能瓶颈。在Try阶段,业务逻辑执行初步操作,如果成功则进入Confirm阶段,确认这些操作;如果在Try阶段出现问题,则会执行Cancel操作,撤销已经完成...
X/Open分布式事务处理模型(XA)使用两阶段提交协议来保证分布式事务的ACID属性(原子性、一致性、隔离性、持久性)。然而,XA协议的同步协商特征使得系统整体可用性降低,性能下降,并且在微服务架构中并不适用。 ...