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

  • 相关阅读:
    配置sql server 2000以允许远程访问
    SQLServer大数据量插入BULK INSERT
    【项目经理之修炼(5)】《基础篇》别把项目成功当目标(转)
    C#XML文件操作类
    winform窗体总在所有窗体最上层
    配置VSS2005的Internet访问(转)
    U盘引导盘制作
    【项目经理之修炼(4)】《基础篇》故事的主角是你吗?(转)
    SQLServer收缩数据库日志
    【项目经理之修炼(1)】《序章》关于要写给谁看的问题(转)
  • 原文地址:https://www.cnblogs.com/duanxz/p/4665130.html
Copyright © 2020-2023  润新知