分布式事务处理两阶段提交实例2

标签: 分布 事务处理 阶段 | 发表时间:2017-01-11 10:44 | 作者:y806839048
出处:http://www.iteye.com

引言:
  Spring 通过AOP技术可以让我们在脱离EJB的情况下享受声明式事务的丰盛大餐。
  通过配合使用ObjectWeb的JOTM开源项目,在不需要Java EE应用服务器的情况下,Spring也可以提供JTA事务。

Sping对JTA支持的三种方式:
  1. 直接集成JOTM提供JTA事务管理(无应用服务器支持,常用于单元测试)
  2. 引用应用服务器(如Tomcat)的JNDI数据源,间接实现JTA事务管理
  3. 使用特定于应用服务器的事务管理器,使用JTA事务的高级功能(Weblogic,Websphere)

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/



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [分布 事务处理 阶段] 推荐:

分布式事务处理两阶段提交实例2

- - 行业应用 - ITeye博客
  Spring 通过AOP技术可以让我们在脱离EJB的情况下享受声明式事务的丰盛大餐.   通过配合使用ObjectWeb的JOTM开源项目,在不需要Java EE应用服务器的情况下,Spring也可以提供JTA事务. Sping对JTA支持的三种方式:. 直接集成JOTM提供JTA事务管理(无应用服务器支持,常用于单元测试).

XA和分布式事务处理

- - 企业架构 - ITeye博客
1、分布式事务处理(DTP)模型. 事务管理器(TM):交易中间件. 资源管理器(RM):通常是数据库. 通信资源管理器(CRM):消息中间件. 本地事务:一个数据库内部的事务处理,如对多个表的操作. 全局事务:DTP环境中的多个数据库的事务处理. 通常多个数据库之间无法知道彼此在做什么,只将自己所做的操作影射到全局事务中,由TM通知和协调相关数据库的提交或回滚.

文章: XA事务处理

- - InfoQ cn
本文选自迷你书 《Java事务设计策略》的第五章,译者翟静. 百度技术沙龙第二十五期:海量数据处理技术解析(4月7日 周六). 为了说明X/Open XA接口在JTA事务管理中的重要性,以及它使用的时机,我们以前一章提到的一段固定收入交易的EJB代码为例:. 这段代码中,首先预置了一笔交易,而后执行交易,这两个操作更改了数据库中不同的表.

消息中间件事务处理

- - 开源软件 - ITeye博客
假设消息中间件没有提供“事务消息”功能,比如你用的是Kafka. (1)Producer端准备1张消息表,把update DB和insert message这2个操作,放在一个DB事务里面. (2)准备一个后台程序,源源不断的把消息表中的message传送给消息中间件. 允许消息重复,但消息不会丢,顺序也不会打乱.

关于分布式事务、两阶段提交、一阶段提交、Best Efforts 1PC模式和事务补偿机制的研究

- - 企业架构 - ITeye博客
XA是由X/Open组织提出的分布式事务的规范. XA规范主要定义了(全局)事务管理器(Transaction Manager)和(局部)资源管理器(Resource Manager)之间的接口. XA接口是双向的系统接口,在事务管理器(Transaction Manager)以及一个或多个资源管理器(Resource Manager)之间形成通信桥梁.

分布式系统中的一致性协议之两阶段提交协议(2PC)

- - 断尘居
 两阶段提交协议是很常见的解决分布式事务的方式,他可以保证分布式事务中,要么所有参与的进程都提交事务成功,要么都取消事务,这样做可以在分布式环境中保持ACID中A(原子性).      在两阶段提交协议中,包含了两种角色:协调者与参与者. 参与者就是实际处理事务的机器,而协调者就是其中一台单独的处理分布式事务的机器.

在spring+hibernaet+mysql事务处理中遇到的一些坑

- - ITeye博客
spring的事务处理本来就是依赖于底层的实现,比如hibernate及数据库本身. 所以,当使用mysql数据库时,首先要确定的是,所操作的对象表是innodb格式的. read-only方法中进行更新或插入操作时,并不总报错. 在service层的方法中定义了事务,并且在spring配置文件中定义了如下的传播方式:.

Fix Bug的五个阶段

- Sirius - 酷壳 - CoolShell.cn
下面的文章和《各种流行的编程方式》有异曲同工,请你不要理解错了. 一个非常严重和困难的bug,能够成就一个饱经沧桑深受压力的有经验的专业程序员的职业生涯. 经受这种考验的创伤程度,相当你受到了一次严重的身体伤害,离婚,或是家庭成为的离世. 研究人员在研究了计算机编程心理学后,得出了一个程序员们在解决一个困难的bug时的心路里程.

逆境心理五阶段

- 冬虫夏草 - 科学松鼠会
原作:http://buttersafe.com/2010/05/20/the-five-stages/.

Nginx请求执行阶段

- - 操作系统 - ITeye博客
    Nginx在处理请求时,按照不同的阶段依次处理,常见的阶段如rewrite、access和content依次执行. Nginx中的指令一般只注册在某一个阶段,如echo注册在content阶段,set注册在rewrite阶段,因此set总是在echo之前执行,与书写顺序无关. 特殊的,geo和map指令与处理阶段无关,它们是声明性的.