Spring全局事务之JBOSS JTA实现Oracle、Ms SqlServer在同一事务中

来源:互联网 发布:手机版轰炸机软件 编辑:程序博客网 时间:2024/05/16 05:36

 

Spring全局事务之JBOSS JTA实现Oracle、Ms SqlServer在同一事务中

  很久以来就一直知道,使用容器事务可以实现多个不同数据源处于同一事务中的功能。苦于没有时间和机会好好实验一把。今天机会难得,化了半天时间做了一个两个Oracle数据源和一个Ms Sql Server数据源在JBoss下的协同事务。下面简单说一下配置和实验情况。

第一、JBoss数据源配置

        要使用JBoss的JTA,首先要做的就是配置链接各种数据源的XA类型的ds文件。


  1、链接Oracle一的数据源,这是一个链接Oracle小型机的oracle-ds.xml 链接文件。配置如下:

      <?xml version="1.0" encoding="UTF-8"?>

<!-- ===================================================================== -->
<!--                                                                       -->
<!--  JBoss Server Configuration                                           -->
<!--                                                                       -->
<!-- ===================================================================== -->

<!-- $Id: oracle-xa-ds.xml 63175 2007-05-21 16:26:06Z rrajesh $ -->

<!-- ===================================================================== -->
<!-- ATTENTION:  DO NOT FORGET TO SET Pad=true IN transaction-service.xml  -->
<!-- ===================================================================== -->

<datasources>
  <xa-datasource>
    <jndi-name>XAOracleDS</jndi-name>
    <track-connection-by-tx/>
    <isSameRM-override-value>false</isSameRM-override-value>
    <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
    <xa-datasource-property name="URL">jdbc:oracle:thin:@(DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.243)(PORT = 1521))(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.244)(PORT = 1521))(LOAD_BALANCE = yes)(CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = GBDATA)))</xa-datasource-property>
    <xa-datasource-property name="User">abc</xa-datasource-property>
    <xa-datasource-property name="Password">abc</xa-datasource-property>
    <!-- Uses the pingDatabase method to check a connection is still valid before handing it out from the pool -->
    <!--valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleValidConnectionChecker</valid-connection-checker-class-name-->
    <!-- Checks the Oracle error codes and messages for fatal errors -->
    <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name>
    <!-- Oracles XA datasource cannot reuse a connection outside a transaction once enlisted in a global transaction and vice-versa -->
    <no-tx-separate-pools/>

      <!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml -->
      <metadata>
         <type-mapping>Oracle9i</type-mapping>
      </metadata>
  </xa-datasource>

  <mbean code="org.jboss.resource.adapter.jdbc.vendor.OracleXAExceptionFormatter"
         name="jboss.jca:service="OracleXAExceptionFormatter">   

    <depends optional-attribute-name="TransactionManagerService">jboss:service=TransactionManager</depends>
  </mbean>

</datasources>

    2、链接Oracle二的数据源,这是一个链接Oracle测试服务器的testoracle-xa-ds.xml链接文件。配置如下

    <?xml version="1.0" encoding="UTF-8"?>

<!-- ===================================================================== -->
<!--                                                                       -->
<!--  JBoss Server Configuration                                           -->
<!--                                                                       -->
<!-- ===================================================================== -->

<!-- $Id: oracle-xa-ds.xml 63175 2007-05-21 16:26:06Z rrajesh $ -->

<!-- ===================================================================== -->
<!-- ATTENTION:  DO NOT FORGET TO SET Pad=true IN transaction-service.xml  -->
<!-- ===================================================================== -->

<datasources>
  <xa-datasource>
    <jndi-name>XAOracleDSTest</jndi-name>
    <track-connection-by-tx/>
    <isSameRM-override-value>false</isSameRM-override-value>
    <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
    <xa-datasource-property name="URL">jdbc:oracle:thin:@(DESCRIPTION =(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.48)(PORT = 1521)))(CONNECT_DATA =(SID = testdb)))</xa-datasource-property>
    <xa-datasource-property name="User">aaa</xa-datasource-property>
    <xa-datasource-property name="Password">aaa</xa-datasource-property>
    <!-- Uses the pingDatabase method to check a connection is still valid before handing it out from the pool -->
    <!--valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleValidConnectionChecker</valid-connection-checker-class-name-->
    <!-- Checks the Oracle error codes and messages for fatal errors -->
    <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name>
    <!-- Oracles XA datasource cannot reuse a connection outside a transaction once enlisted in a global transaction and vice-versa -->
    <no-tx-separate-pools/>

      <!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml -->
      <metadata>
         <type-mapping>Oracle9i</type-mapping>
      </metadata>
  </xa-datasource>

  <mbean code="org.jboss.resource.adapter.jdbc.vendor.OracleXAExceptionFormatter"
         name="jboss.jca:service=OracleXAExceptionFormatterTest">

    <depends optional-attribute-name="TransactionManagerService">jboss:service=TransactionManager</depends>
  </mbean>

</datasources>
  3、链接Sql Server的数据源,mssql-xa-ds.xml配置如下

  <?xml version="1.0" encoding="UTF-8"?>

<!-- ===================================================================== -->
<!--                                                                       -->
<!--  JBoss Server Configuration                                           -->
<!--                                                                       -->
<!-- ===================================================================== -->

<!-- $Id: mssql-xa-ds.xml 63175 2007-05-21 16:26:06Z rrajesh $ -->
  <!-- ==================================================================== -->
  <!-- ConnectionManager setup for xa Microsoft SQL Server 2005, using      -->
  <!-- Microsoft's JDBC driver.                                             -->
  <!-- Thanks to Benjamin Geer  <
benjamin.geer@misys.com>                   -->
  <!-- Be sure to set the JndiName property to the name you want to look up -->
  <!-- the datasource under and set the location of your database in        -->
  <!-- the xa-datasource-property section.                                  -->
  <!-- Further information about the Microsoft JDBC Driver version 1.1      -->
  <!-- can be found here:                                                   -->
  <!--
http://msdn2.microsoft.com/en-us/library/aa496082.aspx               -->
  <!-- ==================================================================== -->


<datasources>
  <xa-datasource>
    <jndi-name>MSSQLXADS</jndi-name>
    <track-connection-by-tx/>
    <isSameRM-override-value>false</isSameRM-override-value>
    <xa-datasource-class>com.microsoft.sqlserver.jdbc.SQLServerXADataSource</xa-datasource-class>
    <xa-datasource-property name="ServerName">192.168.10.15</xa-datasource-property>
    <xa-datasource-property name="DatabaseName">TestData</xa-datasource-property>
    <xa-datasource-property name="SelectMethod">cursor</xa-datasource-property>
<!-- not sure if these should be here-->
    <user-name>SM</user-name>
    <password>123123</password>

      <!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml -->
      <metadata>
         <type-mapping>MS SQLSERVER2000</type-mapping>
      </metadata>
  </xa-datasource>

</datasources>
   配置好三个数据源后,放到JBoss目录下:D:/jboss-4.2.2.GA/server/default/deploy

第二、各种数据源的驱动配置。
    链接Oracle 和Sql Server的驱动,需要放到JBoss的Lib目录中

    Oracle的驱动如下

      ojdbc14.jar、ojdbc14_g.jar

    Sql Server的驱动如下
    msbase.jar、mssqlserver.jar、msutil.jar、sqljdbc.jar(Microsoft SQL Server 2005 JDBC Driver,在此Jar中包含了XA事务所必须的com.microsoft.sqlserver.jdbc.SQLServerXADataSource.class)

    要使用Sql Server2005的XA事务,还需要满足以下条件:

    1、Sql Server2005运行在Window2000或者Window2003环境下

    2、在数据库服务器上运行MSDTC,并且启用XA事务。(在组件服务-->我的电脑,右键属性,可以看到MSDTCx项目)

    3、在数据库的Master库中创建扩展存储过程、根据机器的不同把sqljdbc_xa.dll文件拷贝到sql server的Binn目录下,并在数据库中设置相应权限,详细过程如下:

    1. 将 sqljdbc_xa.dll 从该目录复制到将参与分布式事务的每台 SQL Server 计算机的 Binn 目录下。 

      注意:

        如果使用 32 位处理器,请使用文件夹 x86 中的 sqljdbc_xa.dll。

        如果使用 64 位 x64 处理器,请使用文件夹 x64 中的 sqljdbc_xa.dll。

    2. 在将要参与分布式事务的每台 SQL Server 计算机上执行数据库脚本 xa_install.sql。

    3. 要授予特定用户
      使用 Microsoft SQL Server 2005 JDBC 驱动程序参与分布式事务的权限,请将该用户添加到 SqlJDBCXAUser 角色中。使用什么用户连接Sql Server就需要把该用户加入到SqlJDBCXAUser 角色中
第三、在JBOSS的EJB中使用Spring

    在EJB中使用单例模型创建ApplicationContext对象实例

    public final class AppBeanFactory {

      private static ApplicationContext factory=null;

      private AppBeanFactory() {}

      public static synchronized ApplicationContext getInstance() {

        if(factory == null) {

          factory=new ClassPathXmlApplicationContext("conf/applicationContext.xml");
        }
      }
    }
    applicationContext.xml的详细配置如下:

    <?xml version="1.0" encoding="UTF-8"?>

    <beans
       xmlns="
http://www.springframework.org/schema/beans"
       xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="
http://www.springframework.org/schema/context"
        xmlns:aop="
http://www.springframework.org/schema/aop"
        xmlns:tx="
http://www.springframework.org/schema/tx
      xsi:schemaLocation="
http://www.springframework.org/schema/beans
                  
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
            http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-2.5.xsd
                http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

    <bean id="wmsdstestjndi" class="org.springframework.jndi.JndiObjectFactoryBean">


      <property name="jndiName" value="java:XAOracleDSTest"></property>

    </bean>
    <!-- JNDI获取真实数据源 -->   
     <bean id="wmsdsjndi" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:XAOracleDS"></property>
     </bean>
     <!-- JNDI获取Sql Server数据源 --> 
     <bean id="sqldsjndi" class="org.springframework.jndi.JndiObjectFactoryBean">
      <property name="jndiName" value="java:MSSQLXADS"></property>
     </bean>

    <!-- 定义事务管理器 -->

    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!-- 定义各个数据源对应的jdbcTemplace  -->

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 
        <property name="dataSource"> 
           <ref bean="wmsdstestjndi" /> 
        </property> 
     </bean> 
 
     <bean id="jdbcTemplateebdata" class="org.springframework.jdbc.core.JdbcTemplate"> 
        <property name="dataSource"> 
           <ref bean="wmsdsjndi" /> 
        </property> 
     </bean>  
 
     <bean id="jdbcTemplatesql" class="org.springframework.jdbc.core.JdbcTemplate"> 
        <property name="dataSource"> 
         <ref bean="sqldsjndi" /> 
        </property> 
     </bean>
       

</beans>

在具体的EJB中使用如下样式调用:

  public class OrderForm implements IOrderForm{

    @Transactional(readOnly=false, propagation = Propagation.REQUIRED,rollbackFor=Exception.class)

    public void InsertOrderForm() throws Exception {
      //Oracle一、
      JdbcTemplate myjdbc=(JdbcTemplate)AppBeanFactory.getInstance().getBean("jdbcTemplate");

      this.jdbc.execute("Insert Into OrderFormTest(OrderFormID,FormDate)values('ODZB001',to_date('2009-11-02','YYYY-MM-DD'))");
      //Oracle 二  

      JdbcTemplate myjdbc=(JdbcTemplate)AppBeanFactory.getInstance().getBean("jdbcTemplateebdata");
        myjdbc.execute("Insert into OrderFormSTTest(OrderFormID,ProductID,Qty)values('ODZB001','000001',10)");

       

       //Ms Sql Server
       myjdbc=(JdbcTemplate)AppBeanFactory.getInstance().getBean("jdbcTemplatesql");
        myjdbc.execute("Insert into OrderFormSTTest(OrderFormID,ProductID,Qty)values('ODZB001','000001',10)");
  

      throw new Exception("Error occured in OrderFormST");
  
    }
  }


 第四、把OrderForm类封装进EJB中、以便实现远程调用


    1、远程接口


      @Remote
      public interface ShoppingCart {

         //  添加某个商品信息
          public void addCommodity (String value);

          //  获得客户购买的所有商品的纱衔泥
          public List<String> getCommodity();
      }


    2、远程接口实现


      @Stateful

      public class ShoppingCartBean implements ShoppingCart {

        public void addCommodity(String value) {

          IOrderForm of=(IOrderForm)AppBeanFactory.getInstance().getBean("OrderForm");

          try {
               of.InsertOrderForm();
           } catch (Exception e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
          }
        }
      }
 第五、客户端实现EJB调用

 


  InitialContext ic = new InitialContext();

  ShoppingCart shoppingCart = (ShoppingCart)ic.lookup("ShoppingCartBean/remote");

  shoppingCart.addCommodity("自行车");


  

 

原创粉丝点击