您的位置:首页 > 数据库 > Oracle

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

2009-11-12 22:04 537 查看
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("自行车");

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: