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