How to use JDBC and transactions in Tomcat with JOTM
Target audience
This howto is intended to Servlet/JSP developpers using Tomcat who want to take advantage of distributed transactions when using JDBC code in their servlets
This howto was written based on the JNDI Datasource HOW-TO provided by Tomcat.
It has been written for:
- Tomcat 4.1.18
- JOTM 1.4
It has been successfully reported to work on
- MySQL
- version 4.0.12, using InnoDB
- with mysql-connector-java version 2.0.14
- PostgreSQL
- version 7.3.1
- with pg73jdbc2.jar
1. Introduction
JOTM (Java Open Transaction Manager) is a transaction manager written in Java and implementating JTA (Java Transaction API). It is an Open Source project released under a BSD-style license.
Tomcat is the servlet container that is used in the official Reference Implementation for the Java Servlet and JavaServer Pages (JSP) technologies. Tomcat is released under the Apache Software License
MySQL configuration
Ensure that you follow these instructions as variations can cause problems.
Create a new test user, a new database and a single test table. Your MySQL user must have a password assigned. The driver will fail if you try to connect with an empty password.
mysql> GRANT ALL PRIVILEGES ON *.* TO mojo@localhost
-> IDENTIFIED BY 'jojo' WITH GRANT OPTION;
mysql> create database javatest;
mysql> use javatest;
mysql> create table testdata (
-> id int not null auto_increment primary key,
-> foo int)type=InnoDB;
mysql>
Note: the above user should be removed once testing is complete!
Next insert some test data into the testdata table.
mysql> insert into testdata values(null, 1); Query OK, 1 row affected (0.00 sec) mysql> select * from testdata; +----+-----+ | ID | FOO | +----+-----+ | 1 | 1 | +----+-----+ 1 row in set (0.00 sec) mysql>
PostgreSQL configuration is similar.
Installing Required JARs
In order for a web application to use JOTM, the webapp and Tomcat need to have access to the JOTM jars, as well as the jars it requires
Here is a list of the required jars. They are all included with JOTM 1.4 binary distribution, available at http://www.objectweb.org/jotm
- in the
lib/directoryjotm.jarjotm_jrmp_stubs.jarjonas_timer.jarcarol.jarjta-spec1_0_1.jarjts1_0.jarobjectweb-datasource.jarxapool.jar
All these jar files need to be placed on $TOMCAT_HOME/common/lib/ so that both Tomcat and your web application will see them.
You also need to copy the jar of your JDBC driver to $TOMCAT_HOME/common/lib/.
Configuring JOTM
You'll need to create a file named carol.properties with the following properties:
# lmi stands for Local Method Invocation (it's a "fake" RMI)
carol.protocols=lmi
# do not use CAROL JNDI wrapper
carol.start.jndi=false
# do not start a name server
carol.start.ns=false
this file needs to be placed on $TOMCAT_HOME/common/classes/ so that Tomcat and JOTM will see it.
Configuring Tomcat
server.xml configuration
Now that you've installed JOTM in Tomcat, you need to configure Tomcat so that it can access JDBC and transaction resources. This is done in the dbtest.xml file which will be used by Tomcat to initialize the resources used by your web application.
<Context path="/dbtest" docBase="dbtest.war" debug="0"
reloadable="true" crossContext="true">
<!-- Resource configuration for JDBC datasource
use XAPool
-->
<Resource name="jdbc/myDB" auth="Container"
type="javax.sql.DataSource"/>
<ResourceParams name="jdbc/myDB">
<parameter>
<name>factory</name>
<value>org.objectweb.jndi.DataSourceFactory</value>
</parameter>
<!-- configured by default for PostgreSQL, just change the values
to set it for your database
-->
<parameter><name>username</name><value>mojo</value></parameter>
<parameter><name>password</name><value>jojo</value></parameter>
<parameter><name>driverClassName</name>
<value>org.postgresql.Driver</value></parameter>
<parameter><name>url</name>
<value>jdbc:postgresql://localhost/javatest</value></parameter>
<!--
<parameter><name>driverClassName</name>
<value>org.gjt.mm.mysql.Driver</value></parameter>
<parameter><name>url</name>
<value>jdbc:mysql://localhost/javatest</value></parameter>
-->
</ResourceParams>
<!-- Resource configuration for UserTransaction
use JOTM
-->
<Resource name="UserTransaction" auth="Container"
type="javax.transaction.UserTransaction"/>
<ResourceParams name="UserTransaction">
<parameter>
<name>factory</name>
<value>org.objectweb.jotm.UserTransactionFactory</value>
</parameter>
<parameter>
<name>jotm.timeout</name>
<value>60</value>
</parameter>
</ResourceParams>
</Context>
web.xml configuration
Now you have to configure the web.xml file of your web application
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<resource-env-ref>
<description>
DB Connection
</description>
<resource-env-ref-name>
jdbc/myDB
</resource-env-ref-name>
<resource-env-ref-type>
javax.sql.DataSource
</resource-env-ref-type>
</resource-env-ref>
</web-app>
Test Code
Now create a simple test.jsp for use later.
<html>
<head>
<title>DB Test</title>
</head>
<body>
<%
String completion = request.getParameter("completion");
foo.DBTest test = new foo.DBTest();
test.init(completion);
%>
<h2>Transaction completion</h2>
Transaction completion is :<strong><%= completion %></strong>
<h2>Results</h2>
Int stored in JDBC : <strong><%= test.getFoo() %></strong><br />
<hr />
<form action="test.jsp" method="get">
<input type="radio" name="completion" value="commit" checked="true"> Commit<BR>
<input type="radio" name="completion" value="rollback">Rollback<BR>
<button type="submit">Completion</button>
</form>
</body>
</html>
And create a Java class to actually use your new Datasource and transactions. Note: this code isn't anywhere near production ready - it's only supposed to be used as a simple test :-)
package foo;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import javax.transaction.UserTransaction;
public class DBTest{
int foo = -1;
// value stored in DB
public void init(String completion) {
try{
Context ctx = new InitialContext();
// JDBC stuff
DataSource ds =
(DataSource)ctx.lookup("java:comp/env/jdbc/myDB");
UserTransaction ut = (UserTransaction)ctx.lookup("java:comp/UserTransaction");
java.sql.Connection conn = ds.getConnection();
System.out.println("<<< beginning the transaction >>>");
ut.begin();
// JDBC statements
Statement stmt = conn.createStatement();
ResultSet rst =
stmt.executeQuery("select id, foo from testdata");
if(rst.next()) {
foo=rst.getInt(2);
}
System.out.println("foo = "+ foo +" (before completion)");
PreparedStatement pstmt = conn.prepareStatement("update testdata set foo=? where id=1");
pstmt.setInt(1,++foo);
pstmt.executeUpdate();
if (completion != null && completion.equals("commit")) {
System.out.println("<<< committing the transaction >>>");
ut.commit();
} else {
System.out.println("<<< rolling back the transaction >>>");
ut.rollback();
}
// we set foo to the value stored in the DB
rst =
stmt.executeQuery("select id, foo from testdata");
if(rst.next()) {
foo=rst.getInt(2);
}
System.out.println("foo = "+ foo +" (after completion)");
conn.close();
System.out.println("<<< done >>>");
}catch(Exception e) {
System.out.print("DBTest >> ");
e.printStackTrace();
}
}
public String getFoo() { return ""+foo; }
}
Finally deploy your web app into $CATALINA_HOME/webapps as a warfile called dbtest.war.
Once deployed, point a browser at http://localhost:8080/dbtest/test.jsp to view the fruits of your hard work.
本文针对使用Tomcat的Servlet/JSP开发者,介绍在Tomcat中结合JOTM使用JDBC和事务的方法。涵盖MySQL和PostgreSQL配置、安装所需JAR包、配置JOTM和Tomcat,还给出测试代码,帮助开发者利用分布式事务。

被折叠的 条评论
为什么被折叠?



