因?yàn)樾枰獙㈨?xiàng)目從IBM WebSphere Application Server移植到Tomcat上開發(fā),所以研究了一下在Tomcat中通過JNDI查找和使用JDBC及JTA的方法。
Tomcat 是Servlet容器,但它也提供了一個JNDI InitialContext實(shí)現(xiàn),因此用戶可以像在J2EE應(yīng)用程序服務(wù)器中一樣在Tomcat中使用JNDI查找JDBC數(shù)據(jù)源。不過在事務(wù)處理方面,Tomcat本身并不支持JTA(Java Transaction API),所以需要借助其他的方案。
JOTM(Java Open Transaction Manager)是ObjectWeb的一個開源JTA實(shí)現(xiàn),它本身也是開源應(yīng)用程序服務(wù)器JOnAS(Java Open Application Server)的一部分,為其提供JTA支持和分布式事務(wù)管理。JOTM同樣可以為Tomcat提供JTA支持,以下將對相關(guān)的配置進(jìn)行簡單說明,使用的相應(yīng)版本為:
Tomcat 5.5.x
JOTM 2.0.x
Oracle 9i
1. 配置Tomcat環(huán)境
在$TOMCAT_HOME/conf/context.xml文件中添加以下內(nèi)容:
<Resource name="jdbc/framework" auth="Container"
type="javax.sql.DataSource"
factory="org.objectweb.jndi.DataSourceFactory"
username="user" password="pwd"
driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@172.18.136.200:1521:ORADB"
maxActive="30" maxIdle="30"/>
<Transaction factory="org.objectweb.jotm.UserTransactionFactory"
jotm.timeout="60"/>
2. 添加所需的JAR文件
下載JOTM,將以下文件添加到$TOMCAT_HOME/common/lib/:
jotm.jar
jotm_jrmp_stubs.jar
jotm_iiop_stubs.jar
ow_carol.jar
jta-spec1_0_1.jar
jts1_0.jar
objectweb-datasource.jar
xapool.jar
howl.jar
connector-1_5.jar
同時,還需要添加相應(yīng)數(shù)據(jù)庫的JDBC包,例如Oracle的classes12.jar
3. 配置JOTM
新建一個carol.properties文件,置于$TOMCAT_HOME/common/classes/,文件內(nèi)容如下:
# 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.naming.factory.url.pkgs=org.apache.naming
這樣JOTM將不會使用CAROL JNDI wrapper,從而可以避免類裝載錯誤的發(fā)生
4. 說明
4.1 JOTM目前的版本在JDK1.5或以上可能無法正常運(yùn)行,解決的方法有兩個:使用JDK1.5重新編譯carol庫,或者將Tomcat運(yùn)行在JDK1.4中
4.2 <Transaction>是Tomcat 5中的新標(biāo)記,對于不支持此標(biāo)記的老版本,需要使用以下語句代替事務(wù)資源的聲明:
<!-- Resource configuration for UserTransaction
use JOTM
-->
<Resource name="UserTransaction" auth="Container"
type="javax.transaction.UserTransaction"
factory = "org.objectweb.jotm.UserTransactionFactory"
jotm.timeout = "60"/>
4.3 需要注意的是,使用<Resource>節(jié)點(diǎn)聲明的資源默認(rèn)上下文前綴是"java:comp/env",而使用< Transaction>節(jié)點(diǎn)時則是"java:comp"。因此,當(dāng)使用4.2的方式聲明用戶事務(wù)時,相應(yīng)的JNDI查找代碼也應(yīng)該改為 UserTransaction ut = (UserTransaction)initCtx.lookup("java:comp/env/UserTransaction");
5. 測試
假設(shè)數(shù)據(jù)庫中已經(jīng)做了相應(yīng)配置,可以使用如下jsp頁面進(jìn)行測試:
<!--test.jsp-->
<%@page contentType="text/html;charset=GB2312"%>
<%@page import="java.sql.*"%>
<%@page import="javax.sql.*"%>
<%@page import="javax.naming.*"%>
<%@page import="javax.transaction.UserTransaction"%>
<%
ResultSet rs = null;
Statement stmt = null;
UserTransaction ut = null;
Connection conn = null;
try {
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource ds = (DataSource) envCtx.lookup("jdbc/framework");
ut = (UserTransaction)initCtx.lookup("java:comp/UserTransaction");
conn = ds.getConnection();
ut.begin();
System.out.println("<<< beginning the transaction >>>");
stmt = conn.createStatement(
// ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE
);
rs = stmt.executeQuery("SELECT PRICE FROM TM_PRODUCT WHERE ID=1");
rs.next();
} catch(Exception e) {e.printStackTrace();}
%>
<html>
<body>
Original price:
<%=rs.getString("price")%>
<br>After update:
<%
PreparedStatement pstmt = conn.prepareStatement("update tm_product set price=? where id=1");
pstmt.setInt(1,101);
pstmt.executeUpdate();
rs = stmt.executeQuery("SELECT PRICE FROM TM_PRODUCT WHERE ID=1");
rs.next();
%>
<%=rs.getString("price")%>
<br>After Rollback:
<%
System.out.println("<<< rolling back the transaction >>>");
ut.rollback();//Or ut.commit();
rs = stmt.executeQuery("SELECT PRICE FROM TM_PRODUCT WHERE ID=1");
rs.next();
%>
<%=rs.getString("price")%>
<%conn.close();%>
</body>
</html>
6. 參考
How to use JDBC and transactions in Tomcat with JOTM
How to use JDBC and transactions in Tomcat with JOTM(For Tomcat 5.5.x)
UserTransaction, JOTM and Tomcat 5.5.x
新浪微博:http://t.sina.com.cn/androidguy 昵稱:李寧_Lining