JTA(Java Transaction API )java事务API,主要实现分布式事务管理,跟JDBC主要区别在于JTA可以跨连接,而JDBC事务需要依赖于连接的生命周期
Tomcat是servlet容器,并不支持JTA,需要集成JOTM实现分布式事务管理。
JOTM(Java Open Transaction Manager)是ObjectWeb的一个开源JTA实现,它本身也是开源应用程序服务器JOnAS(Java Open Application Server)的一部分,为其提供JTA支持和分布式事务管理。JOTM同样可以为Tomcat提供JTA支持,以下将对相关的配置进行简单说明
测试环境:
apache-tomcat-6.0.35
ow2-jotm-dist-2.2.1
SQL Server 2005
1添加JOTM JAR文件
将jotm解压后lib文件夹里面的所有jar拷贝到%TOMCAT%/lib目录里面,
还需要把数据库驱动拷贝到%TOMCAT%/lib目录里面(我的数据库驱动是sqljdbc.jar)
2配置JOTM
新建carol.properties文件,放在%TOMCAT_HOME%/lib目录下,内容如下:
# JNDI调用协议
carol.protocols=jrmp
#本地RMI调用
carol.jvm.rmi.local.call=falsecarol.start.jndi=false
#不使用CAROL的JNDI封装器
carol.start.jndi=false
#不启用命名服务器
carol.start.ns=false
#命名工厂类
carol.jndi.java.nameing.factory.url.pkgs=org.apache.nameing
3配置TOMCAT
在%TOMCAT_HOME%/conf/context.xml添加如下内容:
<Resource name="jdbc/afunms"
auth="Container"
type="javax.sql.DataSource"
factory="org.objectweb.jotm.datasource.DataSourceFactory"
driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
username="username"
password="password"
url="jdbc:sqlserver://localhost:1433;databaseName=hibernate" />
<Resource name="UserTransaction"
auth="Container"
type="javax.transaction.UserTransaction" />
<Transaction factory="org.objectweb.jotm.UserTransactionFactory"
jotm.timeout="60" />
4测试:
UserTransaction trans = null;
Connection con = null;
Statement sta = null;
ResultSet res = null;
Context initCtx;
Context envCtx;
DataSource ds;
try {
initCtx = new InitialContext();
envCtx = (Context) initCtx.lookup("java:comp/env");
ds = (DataSource) envCtx.lookup("jdbc/afunms");
trans = (UserTransaction) initCtx
.lookup("java:comp/UserTransaction");
con = ds.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
try {
trans.begin();
System.out.println("<<< beginning the transaction >>>");
} catch (NotSupportedException e) {
e.printStackTrace();
} catch (SystemException e) {
e.printStackTrace();
}
try {
System.out.println("access1");
String sql = null;
sta = con.createStatement();
sql = "SELECT * FROM tb_user WHERE ID= 1";
res = sta.executeQuery(sql);
System.out.println("2");
while (res.next()) {
System.out.println("ID=" + res.getInt(1));
System.out.println("name=" + res.getString(2));
System.out.println("password=" + res.getString(3));
System.out.println("age=" + res.getInt(4));
System.out.println("sex=" + res.getString(5));
}
System.out.println("--------------------------");
sql = "UPDATE tb_user SET username ='zhang' WHERE ID= 1";
sta.executeUpdate(sql);
sql = "SELECT * FROM tb_user WHERE ID= 1";
res = sta.executeQuery(sql);
while (res.next()) {
System.out.println("ID=" + res.getInt(1));
System.out.println("name=" + res.getString(2));
System.out.println("password=" + res.getString(3));
System.out.println("age=" + res.getInt(4));
System.out.println("sex=" + res.getString(5));
}
} catch (Exception e) {
e.printStackTrace();
}
try {
System.out.println("access2");
trans.commit();
} catch (Exception e) {
System.out.println("提交事务异常");
e.printStackTrace();
}
try {
if (res != null)
res.close();
if (sta != null)
sta.close();
if (con != null)
con.close();
} catch (Exception ex) {
ex.printStackTrace();
}
以上代码放在一个servlet的dopost或者doget方法中测试
总结:1对于集成hibernate进行JTA事务管理时,应该把hibernate里面的jta.jar和login.jar包删除掉,因为jotm中存在于jta类似的包,会发生冲突
2在hibernate使用JTA的时候,在提交事务之前session应该session.flush();不然会出现事务不提交的情况
3在配置JOTM的时候carol.jvm.rmi.local.call 必需设置成false,否则在运行时会报如下错误:
java.lang.NoSuchMethodError: sun.rmi.transport.ObjectTable.getStub(Ljava/rmi/Remote;)