研究了几天,终于搞出来了tomcat5.5的JTA事务,把我研究历程拿出来分享下...
首先是jotm的介绍,JOTM 是一个基于Java开放源代码的事务处理管理器。它遵循JTA APIs规范与Business Transaction Protocol(BTP)规范以提供了对Web Service的支持。
首先要明白JTA事务他依赖与一定的数据库与应用服务器,比如oracle,mysql等数据库都支持,应用服务器如jboss等,现在如果你不想用应用服务器的话,我们就需要用jotm(java open transaction manager),java 开发的事务管理器。jotm它只是一个事务管理器!仅此而已... 如果大家想在tomcat中配置JTA事务的话,那么JOTM就是你的首选了.....JOTM有好多版本,由于老版本不支持JDK1.5,所以这里抛开了JOTM2.0以前的版本。选择最新版的ow2-jotm-dist, 他可以支持JDK高版本。
下载地址:http://jotm.objectweb.org
步骤如下:
1.下载好jotm后,把jotm解压,jar包放入tomcat中common/lib文件中,记得把数据库的jar也同时放入。
2.在$TOMCAT_HOME/common/classes/下建立carol.properties文件,内容如下
carol.protocols=jrmp
carol.jvm.rmi.local.call=true
carol.start.jndi=false
carol.start.ns=false
carol.jndi.java.naming.factory.url.pkgs=org.apache.naming
3.配置数据源
在你项目的WEBROOT下的META-INF中建立context.xml
配置两个数据源一个事务对象。
4.开启tomcat后,console控制台会输出
09-6-19 10:40:50 (信) Http11BaseProtocol.start : Starting Coyote HTTP/1.1 on http-8088
09-6-19 10:40:50 (信) ChannelSocket.init : JK: ajp13 listening on /0.0.0.0:8099
09-6-19 10:40:50 (信) JkMain.start : Jk running ID=0 time=0/32 config=null
09-6-19 10:40:50 (信) StoreLoader.load : Find registry server-registry.xml at classpath resource
09-6-19 10:40:50 (信) Catalina.start : Server startup in 6235 ms
等信息,证明JOTM配置成功。
5.然后使用上下文InitialContext()获得事务,开启事务-----两个数据源的操作----关闭事务就可以了。下面介绍我的测试例子。
例子内容:我把详细文件中的内容拷贝如下,大家可以直接拷出测试。
要求:现在有两个数据库,test,mysql这两个MYSQL5.5的数据库。两个数据库中都有一个customer表,表里面有id 自增长的字段,还有name字段。当用户注册时,同时向这两个数据库中加入数据,如果一方失败,则事务失败。
实现步骤:
我建了一个web project,叫JTA。然后把JOTM包拷入TOMCAT/COMMON/lib下,把carol.properties放入到common/classes下面,内容如上所述。
1.接下来我在项目中META-INF下写了数据源的配置文件context.xml,内容如下:
<Context reloadable="true" >
<Resource name="hibernate/jta1"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
username="root" password="123"
factory="org.objectweb.jotm.datasource.DataSourceFactory"
url="jdbc:mysql://127.0.0.1:3306/test" />
<Resource name="hibernate/jta2"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
factory="org.objectweb.jotm.datasource.DataSourceFactory"
username="root" password="123"
url="jdbc:mysql://127.0.0.1:3306/mysql" />
<Resource name="UserTransaction"
auth="Container"
type="javax.transaction.UserTransaction" />
<Transaction factory="org.objectweb.jotm.UserTransactionFactory"
jotm.timeout="60" />
</Context>
2.写一个实体类Customer
package com.tarena.entity;
import java.io.Serializable;
public class Customer implements Serializable{
private Long id;
private String name;
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
}
3.写一个util类,可以通过JNDI名字获得connection对象。
package com.tarena.util;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.*;
public class JDBCUtil {
public static Connection getConnection(String jndi){
Context ctx;
Connection con = null;
try {
ctx = new InitialContext();
System.out.println("ctx"+ctx);
DataSource ds =
(DataSource)ctx.lookup(jndi);
con = ds.getConnection();
System.out.println("con"+con);
} catch (NamingException e) {
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
return con;
}
public static void release(Connection con,Statement sm,ResultSet rs){
try {
if(con!=null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(sm!=null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(rs!=null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
4.写dao层:一个CustomerDAO接口,一个CustomerDaoImpl实现类。
package com.tarena.dao;
import com.tarena.entity.Customer;
public interface CustomerDao {
public boolean addCustomer(Customer c);
}
package com.tarena.dao;
import java.sql.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import com.tarena.entity.Customer;
import com.tarena.util.JDBCUtil;
public class CustomerDaoImpl implements CustomerDao {
public boolean addCustomer(Customer c) {
UserTransaction tx = null;
Connection con = null;
Connection con1 = null;
Statement sm = null;
Statement sm1 = null;
try {
Context ctx = new InitialContext();
System.out.println("ctx"+ctx);//从配置文件中获取事务
tx =(UserTransaction) ctx.lookup("java:comp/UserTransaction");
System.out.println("tx"+tx);
tx.begin();
String sql ="insert into customer(name) values('"+c.getName()+"')";
//通过工具类,获得jta2数据源的连接
con = JDBCUtil.getConnection("java:comp/env/hibernate/jta2");
sm = con.createStatement();
sm.execute(sql);
System.out.println("test数据库增加成功");
//通过工具类,获得jta1数据源的连接
获得jta2数据源的连接con1 = JDBCUtil.getConnection("java:comp/env/hibernate/jta1");
sm1 = con1.createStatement();
sm1.execute(sql);
System.out.println("mysql数据库增加成功");
tx.commit();
return true;
}catch (Exception e) {
e.printStackTrace();
try {
tx.rollback();
} catch (IllegalStateException e1) {
e1.printStackTrace();
} catch (SecurityException e1) {
e1.printStackTrace();
} catch (SystemException e1) {
e1.printStackTrace();
}
e.printStackTrace();
return false;
}finally{
JDBCUtil.release(con, sm, null);
JDBCUtil.release(con1, sm1, null);
}
}
}
5.然后在写了一个servlet,servlet doPost()方法中如下所写:
package com.tarena.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.tarena.dao.*;
import com.tarena.entity.*;
public class CustomerServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
private CustomerDao cd = new CustomerDaoImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("进来了servlet");
String name = request.getParameter("name");
System.out.println("name"+name);
Customer c = new Customer();
c.setName(name);
boolean b = cd.addCustomer(c);
System.out.println(b?"增加成功":"增加失败");
}
}
6.在web.xml中配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>registerServlet</servlet-name>
<servlet-class>com.tarena.servlet.CustomerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>registerServlet</servlet-name>
<url-pattern>/register</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
7.写一个register.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>register.html</title>
</head>
<body>
<center>
<form action="register" method="post">
name:<input type="text" name="name"><br>
<input type="submit" value="submit">
</form>
</center>
</body>
</html>
8,接下来开启服务器。
地址栏输入http://localhost:8080/JTA/register.html
然后执行就可以。
9.如果想测试失败的话,大家可以把其中一个数据库中的表删掉。那么第一个数据库中的记录也将插入失败。
好了,如果有没有测试成功的,可以联系我...