概述 
   【IT168 专稿】Spring 通过AOP技术可以让我们在脱离EJB的情况下享受声明式事务的丰盛大餐,脱离Java EE应用服务器使用声明式事务的道路已经畅通无阻。但是很大部分人都还认为脱离Java EE应用服务器就无法使用JTA事务,这是一个误解。其实,通过配合使用ObjectWeb的JOTM开源项目,不需要Java EE应用服务器,Spring也可以提供JTA事务。

正因为AOP让Spring拥有了脱离EJB容器的声明式事务能力,而JOTM让我们在脱离Java EE应用服务器下拥有JTA事务能力。所以,人们将AOP和JOTM称为Java软件开发的两个圣杯。

本文将讲解Spring在不同环境下提供JTA事务的配置过程,这包括:Spring中直接集成JOTM提供JTA事务管理、将JOTM集成到Tomcat中,Spring通过引用Tomcat JNDI数据源提供JTA事务管理、引用其它功能完善JavaEE应用服务器所提供的JTA事务管理。

    通过集成JOTM,直接在Spring中使用JTA事务 
    JOTM(Java Open Transaction Manager)是ObjectWeb的一个开源JTA实现,它本身也是开源应用程序服务器JOnAS(Java Open Application Server)的一部分,为其提供JTA分布式事务的功能。

Spring 2.0附带的依赖类库中虽然包含jotm类库,但是并不完整,你可以到http://jotm.objectweb.org下载完全版的JOTM。 
Spring为JOTM提供了一个org.springframework.transaction.jta.JotmFactoryBean支持类,通过该支持类可以方便地创建JOTM本地实例。

下面,我们通过配置,使上节中BbtForumImpl#addTopic()方法工作在JTA事务的环境下。addTopic()内部使用两个DAO类(TopicDao和PostDao)分别访问不同数据库中的表。通过下面的步骤说明了使addTopic()方法拥有JTA事务的整个过程:

1. 将JOTM以下类库添加到类路径中: 
    jotm.jar 
    xapool.jar 
    jotm_jrmp_stubs.jar 
    jta-spec1_0_1.jar 
    connector-1_5.jar

2. 编写JOTM配置文件,放到类路径下 
    carol.properties 
    #JNDI调用协议 
    carol.protocols=jrmp 
    #不使用CAROL JNDI封装器 
    carol.start.jndi=false 
    #不启动命名服务器 
    carol.start.ns=false

3. 在MySQL上建立两个数据库 
    在MySQL数据库中运行SQL脚本,建立topicdb和postdb两个数据库,在topicdb数据库中创建t_topic表,在postdb数据库中创建t_post表。我们希望在这两个数据库上进行JTA事务。

4. 在Spring配置文件中配置JOTM 
    代码清单 1 applicationContext-jta.xml 
    …

<!--①JOTM本地实例 -->
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" />
<!--②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" />

首先,我们在①处通过Spring所提供的JotmFactoryBean创建一个本地JOTM实例,该实例同时实现了   javax.transaction.UserTransaction和javax.transaction.TransactionManager接口,它可以和ObjectWeb的XAPool一起工作。 
JTA事务管理器通过userTransaction属性引用本地JOTM实例,Spring的JtaTransactionManager会自动探测到传入的javax.transaction.UserTransaction引用也实现了javax.transaction.TransactionManager,所以我们无需再配置JtaTransactionManager的transactionManager属性,如②所示。 
     在Spring中配置JOTM的另一个关键问题是配置XAPool,支持JTA事务的数据源必须封装成XAPool。首先,我们通过org.enhydra.jdbc.standard.StandardXADataSource 配置一个XA数据源,它指向topicdb数据库,如③-1所示。而后,通过org.enhydra.jdbc.pool.StandardXAPoolDataSource将其封装成一个XAPool,如③所示。按照相同的方式,配置指向postdb数据库的XAPool,如④所示。 
     接下来的配置就顺理成章了,分别使用Spring JDBC的模板类配置DAO类,然后再配置引用DAO类的业务类。关于Spring JDBC的详细内容,参见第10章的内容。 
     这里,我们使用@Transaction注解对业务类BbtForumImpl进行事务声明,所以通过<tx:annotation-driven/>对此进行驱动,BbtForumImpl的代码如下所示: 
代码清单 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());
}
}

BbtForumImpl将Dao类组织起来,PostDao和TopicDao分别访问不同数据库中表,通过Spring注解驱动事务切面的增强后,它们将工作于同一个JTA事务中。

    5. 在Spring中运行测试 
    代码清单 3 TestBbtForumJta

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........");
}
}

通过Spring测试类AbstractDependencyInjectionSpringContextTests的支持,很容易编写一个测试类,对启用了JTA事务的BbtForum#addTopic()方法进行测试。建议你将Log4J设置为DEBUG,这样就可以通过丰富的输出日志观测到JTA事务的执行情况。运行这个测试类后,你将可以看到JTA事务被正确实施。

JTA事务管理--配置剖析的更多相关文章

  1. JTA事务管理--配置剖析(二)

    Spring引用Tomcat的 JTA事务     Tomcat是Servlet容器,但它提供了JNDI的实现,因此用户可以象在Java EE应用程序服务器中一样,在Tomcat中使用JNDI查找JD ...

  2. springboot多数据源+jta事务管理配置

    1.创建一个maven项目,导入相关配置: <?xml version="1.0" encoding="UTF-8"?> <project x ...

  3. spring,mybatis事务管理配置与@Transactional注解使用[转]

    spring,mybatis事务管理配置与@Transactional注解使用[转] spring,mybatis事务管理配置与@Transactional注解使用 概述事务管理对于企业应用来说是至关 ...

  4. JTA事务管理

    何为分布式事务 一个事务包含多个操作,多个操作操作了多个数据源,这样的事务称为分布式事务 和普通事务的区别 单一数据源,事务管理可以借助数据源本地事务完成,实现简单 分布式事务之困难:不可简单的借助数 ...

  5. 事务管理配置与@Transactional注解使用

    spring,mybatis事务管理配置与@Transactional注解使用 概述 事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性. Spring Framewor ...

  6. spring,mybatis事务管理配置与@Transactional注解使用

    spring,mybatis事务管理配置与@Transactional注解使用[转]   spring,mybatis事务管理配置与@Transactional注解使用 概述事务管理对于企业应用来说是 ...

  7. Spring事务管理配置以及异常处理

    Spring事务管理配置: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=" ...

  8. [转]Spring的事务管理难点剖析(1):DAO和事务管理的牵绊

    原文地址:http://stamen.iteye.com/blog/1441758 有些人很少使用Spring而不使用Spring事务管理器的应用,因此常常有人会问:是否用了Spring,就一定要用S ...

  9. spring3.0事务管理配置

    转载:http://war-martin.iteye.com/blog/1396335 第一种配置方法:基于XML的事务管理 这种方法不需要对原有的业务做任何修改,通过在XML文件中定义需要拦截方法的 ...

随机推荐

  1. POJ 3126 Prime Path(BFS求“最短路”)

    题意:给出两个四位数的素数,按如下规则变换,使得将第一位数变换成第二位数的花费最少,输出最少值,否则输出0. 每次只能变换四位数的其中一位数,使得变换后的数也为素数,每次变换都需要1英镑(即使换上的数 ...

  2. 【互联网那些事儿】小度 i 耳目

    关于这个产品是什么,大家自行度. 这里我主要想说的,是百度关于这个产品的一点……呃,“卖萌”的介绍语言. 小度i耳目常见问题 问:为什么叫小度i耳目呢,貌似不太好记忆. 答:名字嘛都是父母起的,不过时 ...

  3. lintcode :搜索二维矩阵

    题目: 搜索二维矩阵 写出一个高效的算法来搜索 m × n矩阵中的值. 这个矩阵具有以下特性: 每行中的整数从左到右是排序的. 每行的第一个数大于上一行的最后一个整数. 样例 考虑下列矩阵: [ [1 ...

  4. *[hackerrank]Consecutive Subsequences

    https://www.hackerrank.com/contests/w6/challenges/consecutive-subsequences 求数组中被k整除的子段和有几个.这个要利用sum[ ...

  5. 如何在React中使用CSS3动画

    一.需求 1.在页面添加item时要有渐变效果 2.单击item可删除,带渐变效果 二.代码 1.通过Reacat插件ReactCSSTransitionGroup实现 <!DOCTYPE ht ...

  6. Delphi 发展历史

    自然人的软件著作权,保护期为自然人终生及其died后50年:软件是合作开发的,截止于最后died的自然人died后第50年的12月31日.法人或者其他组织的软件著作权,保护期为软件首次发表之后50年, ...

  7. 如何删除ArcSde Service服务

    1)打开“控制面板”,“服务”,找到“ArcSde Service(somename)”,这里somename就是你的ArcSde服务的真实的名字,记住这个名字(为叙述方便,以下用somename表示 ...

  8. c语言中static的用法

    1.static定义变量: 1).局部: a.静态局部变量在函数内部定义,生存期为整个源代码,但作用域与自动变量相同,只能在定义的函数里面使用.退出该函数后,虽然此变量还存在内存中,但不能使用. b. ...

  9. 246. Strobogrammatic Number

    题目: A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at ups ...

  10. 87. Scramble String

    题目: Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty subs ...