JOTM 分布式事务初探(JNDI,Tomcat 7 JDBC Pool连接池)

http://jackyin5918.iteye.com/blog/1922379

 

 

JOTM 分布式事务初探(JNDI,Tomcat 7 JDBC Pool连接池)

 

Tomcat 7 带了一个新的连接池 tomcat(The Tomcat JDBC Connection Pool)

网上有人测试,据说性能超过常用连接池(c3p0等).

链接:http://www.open-open.com/lib/view/open1329182303124.html

并且这个连接池提供的连接不是普通的Connection,而是pooledConnection,

而且支持提供XADataSource(org.apache.tomcat.jdbc.pool.XADataSource).

 

The Tomcat JDBC Connection Pool可独立使用,

需要Tomat7版本下lib包中的tomcat-jdbc.jar和bin中的tomcat-juli.jar

 

可以用来做JOTM的分布式事务的数据源.

 

实际使用tomcat版本 是5.5.25

 

JOTM版本 2.1.9 http://jotm.ow2.org/xwiki/bin/view/Main/Download_Releases

 

1. 新建一个Java web工程

 

   将JOTM的lib包下的所有jar包(包括一个空的ext文件夹)拷贝到web-inf的lib下

   

   将Tomcat版本中的tomcat-jdbc.jar和tomcat-juli.jar拷贝到

   tomcat5.5.25的common\lib下,并引入到工程中来.

   

   将 mysql和oracle的jdbc驱动拷贝到web-inf的lib下

   (classes12.jar--oracle驱动,mysql-connector-java-5.1.24-bin.jar--mysql驱动)

   

   需要将web-inf的lib下所有jar包拷贝到tomcat5.5.25的common\lib下,部署的时候,注意将

   webapps\工程\web-inf的lib下的jar全部删除,使用tomcat5.5.25的common\lib下的jar包

 

2. 分别在mysql和oracle中创建测试数据库和测试用户

 

   2.1 mysql数据库(mysql 版本mysql  Ver 14.14 Distrib 5.5.11, for Win32 (x86))

   下面的语句执行前,可能需要使用root用户登陆

   

Sql代码    收藏代码
  1. GRANT ALL PRIVILEGES ON *.* TO mojo@localhost IDENTIFIED BY 'jojo' WITH GRANT OPTION-- 创建用户,并授权  
  2.    create database javatest;  
  3.    use javatest;  
  4.    create table testdata (id int not null auto_increment primary key,foo int) engine = innodb;  
  5.    create unique index index_idfoo on testdata(id,foo); --创建唯一索引  

 

   

   2.2 oracle数据

   

   

Sql代码    收藏代码
  1. create user mojo identified by jojo;  
  2.    grant dba to mojo;--授予DBA权限    
  3.    connect mojo/jojo@serviceid; -- 使用刚刚创建的用户登陆 serviceid 需要修改成实际的  
  4.    create table testdata (id number(10),foo number(10)); --创建一个表  
  5.    create unique index index_idfoo on testdata(id,foo);  
  6.    commit;  

 

   

3. 配置carol.properties,放置到src目录下面

 

    # # JNDI (Protocol Invocation)

    carol.protocols=jrmp

    

    # Local RMI Invocation

    carol.jvm.rmi.local.call=true

    

    # do not use CAROL JNDI wrapper

    carol.start.jndi=false

    

    # do not start a name server

    carol.start.ns=false

    

    # Naming Factory

    carol.jndi.java.nameing.factory.url.pkgs=org.apache.nameing

   

4. 配置tomcat/conf/context.xml

 

  

Xml代码    收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.   <Context>  
  3.       <Resource name="jdbc/mysqlDB"  
  4.             auth="Container"  
  5.             type="javax.sql.DataSource"  
  6.             factory="org.objectweb.jotm.datasource.DataSourceFactory"  
  7.             testWhileIdle="true"  
  8.             testOnBorrow="true"  
  9.             testOnReturn="false"  
  10.             validationQuery="SELECT 1"  
  11.             validationInterval="30000"  
  12.             timeBetweenEvictionRunsMillis="30000"  
  13.             maxActive="100"  
  14.             minIdle="10"  
  15.             maxWait="10000"  
  16.             initialSize="10"  
  17.             removeAbandonedTimeout="60"  
  18.             removeAbandoned="true"  
  19.             logAbandoned="true"  
  20.             minEvictableIdleTimeMillis="30000"  
  21.             jmxEnabled="true"  
  22.             jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;  
  23.               org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"  
  24.             username="mojo"  
  25.             password="jojo"  
  26.             driverClassName="com.mysql.jdbc.Driver"  
  27.             url="jdbc:mysql://127.0.0.1:3306/javatest"/>  
  28.               
  29.       <Resource name="jdbc/oracleDB"  
  30.             auth="Container"  
  31.             type="javax.sql.DataSource"  
  32.             factory="org.objectweb.jotm.datasource.DataSourceFactory"  
  33.             testWhileIdle="true"  
  34.             testOnBorrow="true"  
  35.             testOnReturn="false"  
  36.             validationQuery="SELECT 1"  
  37.             validationInterval="30000"  
  38.             timeBetweenEvictionRunsMillis="30000"  
  39.             maxActive="100"  
  40.             minIdle="10"  
  41.             maxWait="10000"  
  42.             initialSize="10"  
  43.             removeAbandonedTimeout="60"  
  44.             removeAbandoned="true"  
  45.             logAbandoned="true"  
  46.             minEvictableIdleTimeMillis="30000"  
  47.             jmxEnabled="true"  
  48.             jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;  
  49.               org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"  
  50.             username="mojo"  
  51.             password="jojo"  
  52.             driverClassName="oracle.jdbc.driver.OracleDriver"  
  53.             url="jdbc:oracle:thin:@10.47.170.175:1521:zxin"/>  
  54.               
  55.       <!-- Resource configuration for UserTransaction  
  56.              use JOTM  
  57.       -->  
  58.       <Transaction factory="org.objectweb.jotm.UserTransactionFactory" jotm.timeout="60"/>  
  59.            
  60.     
  61.       <WatchedResource>WEB-INF/web.xml</WatchedResource>  
  62.       
  63.       <!-- Uncomment this to disable session persistence across Tomcat restarts -->  
  64.       <!-- 
  65.       <Manager pathname="" /> 
  66.       -->  
  67.     
  68.   </Context>  

 上面配置文件中 factory="org.objectweb.jotm.datasource.DataSourceFactory"

 表示使用的是JOMT自己的连接池.

 而配置成 factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"

 表示使用 Tomcat 7 JDBC 连接池

 

注意上面配置数据库连接时,

type="javax.sql.DataSource"

factory="org.objectweb.jotm.datasource.DataSourceFactory"

两个属性,type总是DataSource,尽管JOTM要求提供XADataSource,

主要是factory="org.objectweb.jotm.datasource.DataSourceFactory"这个可以根据需要

选择提供普通的DataSource或者XADataSource.

这样,假如之前有相关的配置,则修改为支持JOTM分布式事务时,貌似只要修改这个

factory配置即可.

 

<Transaction>是Tomcat 5中的新标记,对于不支持此标记的老版本,

需要使用以下语句代替事务资源的声明:

 

Xml代码    收藏代码
  1. <!-- Resource configuration for UserTransaction  
  2. use JOTM  
  3. -->  
  4. <Resource name="UserTransaction" auth="Container"  
  5. type="javax.transaction.UserTransaction"  
  6. factory = "org.objectweb.jotm.UserTransactionFactory"  
  7. jotm.timeout = "60"/>  

 

需要注意的是,使用<Resource>节点声明的资源默认上下文前缀是"java:comp/env",

而使用< Transaction>节点时则是"java:comp"。因此,当使用4.2的方式声明用户事务时,

相应的JNDI查找代码也应该改为 

UserTransaction ut = (UserTransaction)initCtx.lookup("java:comp/env/UserTransaction");

上面的配置还配置了一个 UserTransaction.

 

5. 在Java类中获取上面配置的资源

 

   

Java代码    收藏代码
  1. Context ctx = new InitialContext();  
  2.   
  3.    // JDBC stuff  
  4.    DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/mysqlDB"); //mysql数据源  
  5.         
  6.    DataSource dsOra = (DataSource) ctx.lookup("java:comp/env/jdbc/oracleDB");//oarcle数据源  
  7.         
  8.    UserTransaction ut = (UserTransaction) ctx.lookup("java:comp/UserTransaction"); //用户事务(分布式)  

 

   

6. 测试分布式事务.

 

   上面在mysql和oracle中分别创建了一个表,并且表里面数据不能重复.

   

   初始化时在mysql中插入一条语句:

   insert into testdata(id,foo) values(1,1);

   

   然后在程序中处理:

   (1) 启动用户事务

   (2) 在oracle中插入语句insert into testdata(id,foo) values(1,1); --oracle是首次插入这个语句

   (3) 在mysql中重复插入数据

   (4) 如果一切正常提交事务,否则回滚事务

   

   分析: 假如不使用分布式事务,则oracle插入数据成功,mysql插入数据失败(重复插入).

   但是现在使用分布式事务,回滚时,导致oracle中的数据也回滚.

   所以上面4个步骤执行完毕后,oracle中仍然没有数据.

   

   测试代码:

   

Java代码    收藏代码
  1. package foo;  
  2.   
  3. import java.sql.Statement;  
  4.   
  5. import javax.naming.Context;  
  6. import javax.naming.InitialContext;  
  7. import javax.sql.DataSource;  
  8. import javax.transaction.UserTransaction;  
  9.   
  10. public class DBTest  
  11. {  
  12.   
  13.   int foo = -1;  
  14.   
  15.   // value stored in DB  
  16.   
  17.   public void init(String completion)  
  18.   {  
  19.     UserTransaction ut = null;  
  20.     try  
  21.     {  
  22.       Context ctx = new InitialContext();  
  23.   
  24.       // mysql数据源  
  25.       DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/mysqlDB");  
  26.       //oracle数据源  
  27.       DataSource dsOra = (DataSource) ctx.lookup("java:comp/env/jdbc/oracleDB");  
  28.       //用户事务(分布式)  
  29.       ut = (UserTransaction) ctx.lookup("java:comp/UserTransaction");  
  30.         
  31.         
  32.       java.sql.Connection conn = ds.getConnection();  
  33.       java.sql.Connection connOra = dsOra.getConnection();  
  34.         
  35.       System.out.println("<<< beginning the transaction >>>");  
  36.       ut.begin();  
  37.         
  38.       //oracle中插入数据  
  39.       Statement stmtOra =connOra.createStatement();  
  40.       stmtOra.execute("insert into testdata(id,foo) values(1,1)");  
  41.   
  42.       // mysql中插入数据(之前表里面已经有一样的数据,导致下面的插入数据失败)  
  43.       Statement stmt = conn.createStatement();  
  44.       stmt.execute("insert into testdata(id,foo) values(1,1)");  
  45.       //mysql 中插入失败导致整个事务回滚,oracle也回滚了,导致oracle中仍然没有数据.  
  46.         
  47.   
  48.       System.out.println("<<< committing the transaction >>>");  
  49.       ut.commit();  
  50.   
  51.       stmt.close();  
  52.       stmtOra.close();  
  53.   
  54.       conn.close();  
  55.       connOra.close();  
  56.         
  57.       System.out.println("<<< done >>>");  
  58.     }  
  59.     catch (Exception e)  
  60.     {  
  61.       try  
  62.       {  
  63.         System.out.println("<<< rollbacking the transaction >>>");  
  64.         ut.rollback();  
  65.       }  
  66.       catch (Exception es)  
  67.       {  
  68.         System.out.println("rollbacking error >> ");  
  69.         es.printStackTrace();  
  70.       }  
  71.         
  72.       System.out.println("DBTest >> ");  
  73.       e.printStackTrace();  
  74.     }  
  75.   }  
  76.   
  77.   public String getFoo()  
  78.   {  
  79.     return "" + foo;  
  80.   }  
  81. }  

 

   

参考 :http://static.raibledesigns.com/downloads/howto-tomcat-jotm.html

 

http://static.raibledesigns.com/downloads/howto-tomcat-jotm.html

 

http://www.blogjava.net/nokiaguy/archive/2008/05/08/199150.html

猜你喜欢

转载自liuguofeng.iteye.com/blog/2088585