zoukankan      html  css  js  c++  java
  • JTA事务管理--配置剖析

    概述 
       【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事务被正确实施。 

  • 相关阅读:
    svn command line tag
    MDbg.exe(.NET Framework 命令行调试程序)
    Microsoft Web Deployment Tool
    sql server CI
    VS 2010 One Click Deployment Issue “Application Validation did not succeed. Unable to continue”
    mshtml
    大厂程序员站错队被架空,只拿着五折工资!苟活和离职,如何选择?
    揭秘!Windows 为什么会蓝屏?微软程序员竟说是这个原因...
    喂!千万别忘了这个C语言知识!(~0 == -1 问题)
    Linux 比 Windows 更好,谁反对?我有13个赞成理由
  • 原文地址:https://www.cnblogs.com/duanxz/p/4665130.html
Copyright © 2011-2022 走看看