概述 
   【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 
    …

  1. <!--①JOTM本地实例 -->
  2. <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" />
  3. <!--②JTA事务管理器 -->
  4. <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
  5. <property name="userTransaction" ref="jotm" /> <!--②-1:指定userTransaction属性-->
  6. </bean>
  7. <!--③XAPool配置,内部包含了一个XA数据源,对应topicdb数据库-->
  8. <bean id="topicDS" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
  9. <property name="dataSource">
  10. <!--③-1:内部XA数据源 -->
  11. <bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
  12. <property name="transactionManager" ref="jotm" />
  13. <property name="driverName" value="com.MySQL.jdbc.Driver" />
  14. <property name="url" value="jdbc:MySQL://localhost:3309/topicdb" />
  15. </bean>
  16. </property>
  17. <property name="user" value="root" />
  18. <property name="password" value="1234" />
  19. </bean>
  20. <!--④按照③相似的方式配置另一个XAPool,对应postdb数据库, -->
  21. <bean id="postDS" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
  22. <property name="dataSource">
  23. <bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
  24. <property name="transactionManager" ref="jotm" />
  25. <property name="driverName" value="com.mysql.jdbc.Driver" />
  26. <property name="url" value="jdbc:mysql://localhost:3309/postdb" />
  27. </bean>
  28. </property>
  29. <property name="user" value="root" />
  30. <property name="password" value="1234" />
  31. </bean>
  32. <!--⑤配置访问topicDB数据源的Spring JDBC模板 -->
  33. <bean id="topicTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  34. <property name="dataSource" ref="topicDS" />
  35. </bean>
  36. <!--⑥配置访问postDB数据源的Spring JDBC模板 -->
  37. <bean id="postTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  38. <property name="dataSource" ref="postDS" />
  39. </bean>
  40. <!--⑦基于topicTemplate数据源的topicDao -->
  41. <bean id="topicDao" class="com.baobaotao.dao.jdbc.TopicJdbcDao">
  42. <property name="jdbcTemplate" ref="topicTemplate" />
  43. </bean>
  44. <!--⑧基于postTemplate数据源的postDao -->
  45. <bean id="postDao" class="com.baobaotao.dao.jdbc.PostJdbcDao">
  46. <property name="jdbcTemplate" ref="postTemplate" />
  47. </bean>
  48. <!--⑨进行跨数据库JTA事务的业务类-->
  49. <bean id="bbtForum" class="com.baobaotao.service.impl.BbtForumImpl">
  50. <property name="topicDao" ref="topicDao" />
  51. <property name="postDao" ref="postDao" />
  52. </bean>
  53. <!--⑩对BbtForumImpl业务类中的@Transaction注解进行驱动,以织入事务管理切面 -->
  54. <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

  1. package com.baobaotao.service.impl;
  2. import org.springframework.transaction.annotation.Transactional;
  3. import com.baobaotao.dao.PostDao;
  4. import com.baobaotao.dao.TopicDao;
  5. import com.baobaotao.domain.Forum;
  6. import com.baobaotao.domain.Topic;
  7. import com.baobaotao.service.BbtForum;
  8. @Transactional// ①事务注解,以便Spring动态织入事务管理功能
  9. public class BbtForumImpl implements BbtForum {
  10. private TopicDao topicDao;
  11. private PostDao postDao;
  12.  
  13. public void addTopic(Topic topic) throws Exception {
  14. //②将方法将被施加JTA事务的增强
  15. topicDao.addTopic(topic);
  16. postDao.addPost(topic.getPost());
  17. }
  18. }

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

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

  1. package com.baobaotao.service;
  2. import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
  3.  
  4. public class TestBbtForumJta extends AbstractDependencyInjectionSpringContextTests{
  5.  
  6. private BbtForum bbtForum;
  7. private final Logger logger = Logger.getLogger(getClass());
  8.  
  9. public void setBbtForum(BbtForum bbtForum) {
  10. this.bbtForum = bbtForum;
  11. }
  12.  
  13. protected String[] getConfigLocations() {
  14. return new String[]{"classpath:applicationContext-jta.xml"};
  15. }
  16.  
  17. public void testAddPost() throws Exception{
  18. logger.info("begin........");
  19. Topic topic = new Topic();
  20. topic.setTopicTitle("Title -pfb");
  21. Post post = new Post();
  22. post.setPostText("post content -pfb");
  23. topic.setPost(post);
  24. bbtForum.addTopic(topic);
  25. //①使用了JTA事务的业务方法
  26. logger.info("end........");
  27. }
  28. }

通过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 2309 BST(找规律的题)

    题意:给出一棵二分搜索树,再给一个节点编号n,求以这个节点为根节点的子树叶子节点的最大值与最小值. 首先求n所在的层数,他的层数就是他的因子中2的个数(规律). n的左右各有num=2^i-1个数.最 ...

  2. POJ1442Black Box

    http://poj.org/problem?id=1442 题意 : 题目中对给出的数字有两种操作ADD(I)操作,将ADD括号里的数字 I 加到数列里边去,然后是自动排好序的,每一个数列前边都会有 ...

  3. 乳草的入侵//BFS

    P1030 乳草的入侵 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 USACO OCT09 6TH 描述 Farmer John一直努力让他的草地充满鲜美 ...

  4. lintcode:落单的数

    题目: 落单的数 给出2*n + 1 个的数字,除其中一个数字之外其他每个数字均出现两次,找到这个数字. 样例 给出 [1,2,2,1,3,4,3],返回 4 挑战 一次遍历,常数级的额外空间复杂度 ...

  5. Go语言的优点(oschina讨论)

    Go语言的优点:并发/网络/性能/工具(fmt/pprof/test)/标准库(http/json/log/flags/atomic)/GoogleGo语言垃圾回收器真正致命的缺陷是,会导致整个进程不 ...

  6. Delphi语言获得生命的原因和过程

    都说Anders Hejlsberg是Delphi语言的作者,前一阵仔细读了VCL源码,惊叹于它的巧夺天工,未免对编译器的作者有些不服气,觉得首功不是他.今天仔细想了想,还是觉得不服不行.以下是我的理 ...

  7. Android:储存方式之SharePreferences

    使用SharedPreferences保存数据,其实质是采用了xml文件存放数据, 存储位置:/data/data/<package name>/shared_prefs 写入: publ ...

  8. C#基础练习(使用委托窗体传值)

    主界面: Form1中的代码: namespace _06委托练习_窗体传值 {     public partial class Form1 : Form     {         public ...

  9. /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.15' not found错误的解决

    升级cmake时,提示"Error when bootstrapping CMake:Problem while running initial CMake",第二次运行./boo ...

  10. .net 程序员成长路线图?

    https://www.zhihu.com/question/25474641 得看赵四本, @赵劼 推荐的. CLR via C# .net Essentials C# in Depth Frame ...