JTA事务和JDBC事务

一般情况下,J2EE应用服务器支持JDBC事务、JTA事务、容器管理事务。这里讨论JTA和JDBC事务的区别。这2个是常用的DAO模式事务界定方式。
JDBC 事务
JDBC 事务是用 Connection 对象控制的。JDBC Connection 接口( java.sql.Connection )提供了两种事务模式:自动提交和手工提交。
★ 在jdbc中,事务操作缺省是自动提交。也就是说,一条对数据库的更新表达式代表一项事务操作,操作成功后,系统将自动调用commit()来提交,否则将调用rollback()来回滚。
★ 在jdbc中,可以通过调用setAutoCommit(false)来禁止自动提交。之后就可以把多个数据库操作的表达式作为一个事务,在操作完成后调用commit()来进行整体提交,倘若其中一个表达式操作失败,都不会执行到commit(),并且将产生响应的异常;此时就可以在异常捕获时调用 rollback()进行回滚。这样做可以保持多次更新操作后,相关数据的一致性,示例如下:

Java代码

 1.   try {  
2.
3. conn =
4.
5. DriverManager.getConnection
6.
7. ("jdbc:oracle:thin:@host:1521:SID","username","userpwd";
8.
9. conn.setAutoCommit(false);//禁止自动提交,设置回滚点
10.
11. stmt = conn.createStatement();
12.
13. stmt.executeUpdate(“alter table …”); //数据库更新操作1
14.
15. stmt.executeUpdate(“insert into table …”); //数据库更新操作2
16.
17. conn.commit(); //事务提交
18.
19. }catch(Exception ex) {
20.
21. ex.printStackTrace();
22.
23. try {
24.
25. conn.rollback(); //操作不成功则回滚
26.
27. }catch(Exception e) {
28.
29. e.printStackTrace();
30.
31. }
32.
33. }

try {

conn =

DriverManager.getConnection

("jdbc:oracle:thin:@host:1521:SID","username","userpwd";

conn.setAutoCommit(false);//禁止自动提交,设置回滚点

stmt = conn.createStatement();

stmt.executeUpdate(“alter table …”); //数据库更新操作1

stmt.executeUpdate(“insert into table …”); //数据库更新操作2

conn.commit(); //事务提交

}catch(Exception ex) {

ex.printStackTrace();

try {

conn.rollback(); //操作不成功则回滚

}catch(Exception e) {

e.printStackTrace();

}

}


JDBC 事务的一个缺点是事务的范围局限于一个数据库连接。一个 JDBC 事务不能跨越多个数据库。

[color=red]JTA事务

JTA(Java Transaction API) 为 J2EE 平台提供了分布式事务服务。
要用 JTA 进行事务界定,应用程序要调用 javax.transaction.UserTransaction 接口中的方法。JTA事务需要application server提供支持,创建transactionManager对象,进行分布式事务。但是tomcat不提供transactionManager服务,jboss和weblogic提供支持。tomcat可以结合spring提供支持[/color]
例如: utx.begin();

Java代码

1. // ...  
2. DataSource ds = obtainXADataSource();
3. Connection conn = ds.getConnection();
4. pstmt = conn.prepareStatement("UPDATE MOVIES ...");
5. pstmt.setString(1, "Spinal Tap");
6. pstmt.executeUpdate();
7. // ...
8. utx.commit();

// ...
DataSource ds = obtainXADataSource();
Connection conn = ds.getConnection();
pstmt = conn.prepareStatement("UPDATE MOVIES ...");
pstmt.setString(1, "Spinal Tap");
pstmt.executeUpdate();
// ...
utx.commit();


让我们来关注下面的话:
“用 JTA 界定事务,那么就需要有一个实现 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驱动程序。一个实现了这些接口的驱动程序将可以参与 JTA 事务。一个 XADataSource 对象就是一个 XAConnection 对象的工厂。 XAConnection s 是参与 JTA 事务的 JDBC 连接。”
要使用JTA事务,必须使用XADataSource来产生数据库连接,产生的连接为一个XA连接。
XA连接(javax.sql.XAConnection)和非XA(java.sql.Connection)连接的区别在于:XA可以参与JTA的事务,而且不支持自动提交。
Note:
Oracle, Sybase, DB2, SQL Server等大型数据库才支持XA, 支持分布事务。
My SQL 连本地都支持不好,更别说分布事务了。
JTA方式的实现过程:
用XADataSource产生的XAConnection它扩展了一个getXAResource()方法,事务通过这个方法把它加入到事务容器中进行管理.对于调用者来说,根本看不到事务是如果管理的,你只要声明开始事务,告诉容器我下面的操作要求事务参与了,最后告诉事务说到这儿可以提交或回滚了, 别的都是黑箱操作。
在使用JTA之前,你必须首先实现一个Xid类用来标识事务(在普通情况下这将由事务管理程序来处理)。Xid包含三个元素:formatID、 gtrid(全局事务标识符)和bqual(分支修饰词标识符)。
下面的例子说明Xid的实现:
Java代码

 1. import javax.transaction.xa.*;   
2. public class MyXid implements Xid
3. {
4.  protected int formatId;
5.  protected byte gtrid[];
6.  protected byte bqual[];
7.  public MyXid()
8.   {
9.  }
10.  public MyXid(int formatId, byte gtrid[], byte bqual[])
11.   {
12.   this.formatId = formatId;
13.   this.gtrid = gtrid;
14.   this.bqual = bqual;
15.   }
16.
17.  public int getFormatId()
18.   {
19.   return formatId;
20.   }
21.
22.  public byte[] getBranchQualifier()
23.   {
24.   return bqual;
25.   }
26.
27.  public byte[] getGlobalTransactionId()
28.   {
29.   return gtrid;
30.   }
31.
32. }

import javax.transaction.xa.*;
public class MyXid implements Xid
{
 protected int formatId;
 protected byte gtrid[];
 protected byte bqual[];
 public MyXid()
 {
 }
 public MyXid(int formatId, byte gtrid[], byte bqual[])
 {
  this.formatId = formatId;
  this.gtrid = gtrid;
  this.bqual = bqual;
 }

 public int getFormatId()
 {
  return formatId;
 }

 public byte[] getBranchQualifier()
 {
  return bqual;
 }

 public byte[] getGlobalTransactionId()
 {
  return gtrid;
 }

}


其次,你需要创建一个你要使用的数据库的数据源:

Java代码 收藏代码

1. public DataSource getDataSource()
2.  throws SQLException
3.   {
4.   SQLServerDataSource xaDS = new
5.    com.merant.datadirect.jdbcx.sqlserver.SQLServerDataSource();
6.   xaDS.setDataSourceName("SQLServer");
7.   xaDS.setServerName("server");
8.   xaDS.setPortNumber(1433);
9.   xaDS.setSelectMethod("cursor");
10.   return xaDS;
11. }

public DataSource getDataSource()
 throws SQLException
 {
  SQLServerDataSource xaDS = new
  com.merant.datadirect.jdbcx.sqlserver.SQLServerDataSource();
  xaDS.setDataSourceName("SQLServer");
  xaDS.setServerName("server");
  xaDS.setPortNumber(1433);
  xaDS.setSelectMethod("cursor");
  return xaDS;
}



  
例1?这个例子是用“两步提交协议”来提交一个事务分支:

Java代码

  1. XADataSource xaDS;   
2. XAConnection xaCon;
3. XAResource xaRes;
4. Xid xid;
5. Connection con;
6. Statement stmt;
7. int ret;
8. xaDS = getDataSource();
9. xaCon = xaDS.getXAConnection("jdbc_user", "jdbc_password");
10. xaRes = xaCon.getXAResource();
11. con = xaCon.getConnection();
12. stmt = con.createStatement();
13. xid = new MyXid(100, new byte[]{0x01}, new byte[]{0x02});
14. try {
15.    xaRes.start(xid, XAResource.TMNOFLAGS);
16.    stmt.executeUpdate("insert into test_table values (100)");
17.   xaRes.end(xid, XAResource.TMSUCCESS);
18.    ret = xaRes.prepare(xid);
19.   if (ret == XAResource.XA_OK) {
20.     xaRes.commit(xid, false);
21.    }
22. }
23. catch (XAException e) {
24.   e.printStackTrace();
25. }
26. finally {
27.   stmt.close();
28.  con.close();
29.   xaCon.close();
30. }

XADataSource xaDS;
XAConnection xaCon;
XAResource xaRes;
Xid xid;
Connection con;
Statement stmt;
int ret;
xaDS = getDataSource();
xaCon = xaDS.getXAConnection("jdbc_user", "jdbc_password");
xaRes = xaCon.getXAResource();
con = xaCon.getConnection();
stmt = con.createStatement();
xid = new MyXid(100, new byte[]{0x01}, new byte[]{0x02});
try {
  xaRes.start(xid, XAResource.TMNOFLAGS);
  stmt.executeUpdate("insert into test_table values (100)");
  xaRes.end(xid, XAResource.TMSUCCESS);
  ret = xaRes.prepare(xid);
  if (ret == XAResource.XA_OK) {
    xaRes.commit(xid, false);
   }
}
catch (XAException e) {
 e.printStackTrace();
}
finally {
 stmt.close();
 con.close();
 xaCon.close();
}



当然,实际过程中,我们不需要写这些代码,这些代码是JTA最终的实现代码。
关于“两步提交协议”,可以参看下面的文章:

http://www.jspcn.net/htmlnews/11049371131251752.html
http://www.vermicelli.pasta.cs.uit.no/ipv6/students/andrer/doc/html/node18.html


选择最好的方式
用 JDBC API 进事务界定来构建 DAO 类的。这些 DAO 类可以总结如下:

事务界定代码嵌入在 DAO 类中。
DAO 类使用 JDBC API 进行事务界定。
调用者不能界定事务。
事务范围局限于单个 JDBC 连接。
JDBC 事务并不总是适合复杂的企业应用程序。如果您的事务要跨越多个 DAO 或者多个数据库,那么下列实现策略也许更合适:

事务用 JTA 界定。
事务界定代码从 DAO 中分离出来。
调用者负责界定事务。
DAO 加入一个全局事务。
JDBC 方式由于其简单性而具有吸引力,JTA 方式提供了更大的灵活性。您所选择的实现将取决于应用程序的特定需求。
XADataSource例子:

Java代码 收藏代码

1. <?xml version="1.0" encoding="UTF-8"?>
2.
3. <!-- ===================================================================== -->
4. <!-- -->
5. <!-- JBoss Server Configuration -->
6. <!-- Thanks to Horia Muntean <horia@bvb.ro> -->
7. <!-- ===================================================================== -->
8.
9. <!-- $Id: db2-xa-ds.xml,v 1.1.2.1 2003/05/30 18:25:57 d_jencks Exp $ -->
10.
11.
12. <datasources>
13. <!--
14. XADatasource for DB2 V8.1 (app driver)
15. copy $db2_install_dir/java/db2java.zip into $jboss_install_dir/server/default/lib
16. -->
17.
18. <xa-datasource>
19. <jndi-name>DB2XADS</jndi-name>
20. <xa-datasource-class>COM.ibm.db2.jdbc.DB2XADataSource</xa-datasource-class>
21. <xa-datasource-property name="DatabaseName">yout_database_name</xa-datasource-property>
22. <xa-datasource-property name="User">your_user</xa-datasource-property>
23. <xa-datasource-property name="Password">your_password</xa-datasource-property>
24. </xa-datasource>
25. </datasources>

<?xml version="1.0" encoding="UTF-8"?>

<!-- ===================================================================== -->
<!-- -->
<!-- JBoss Server Configuration -->
<!-- Thanks to Horia Muntean <horia@bvb.ro> -->
<!-- ===================================================================== -->

<!-- $Id: db2-xa-ds.xml,v 1.1.2.1 2003/05/30 18:25:57 d_jencks Exp $ -->


<datasources>
<!--
XADatasource for DB2 V8.1 (app driver)
copy $db2_install_dir/java/db2java.zip into $jboss_install_dir/server/default/lib
-->

<xa-datasource>
<jndi-name>DB2XADS</jndi-name>
<xa-datasource-class>COM.ibm.db2.jdbc.DB2XADataSource</xa-datasource-class>
<xa-datasource-property name="DatabaseName">yout_database_name</xa-datasource-property>
<xa-datasource-property name="User">your_user</xa-datasource-property>
<xa-datasource-property name="Password">your_password</xa-datasource-property>
</xa-datasource>
</datasources>


引用:
http://www.jspcn.net/htmlnews/11049371131251752.htmlhttp://www-128.ibm.com/developerworks/cn/java/j-dao/
http://www.vermicelli.pasta.cs.uit.no/ipv6/students/andrer/doc/html/node18.html
Spring+iBatis+JOTM实现JTA事务: 如何处理跨库事物:spring + jtom 的jta事务是个很好的选择. 这个源码示例非常不错,包括所有的源码和jar包,下载后eclipse 或 myeclipse 导入就能用。 里面有详细的说明和注释,欢迎下载传播。有问题请在评价中留言,我会及时回复的。 <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/> <!-- JTA事务管理器 --> <bean id="myJtaManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="userTransaction"> <ref local="jotm"/> </property> </bean> <!-- 数据源A --> <bean id="dataSourceA" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown"> <property name="dataSource"> <bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown"> <property name="transactionManager" ref="jotm"/> <property name="driverName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> </bean> </property> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- 数据源B --> <bean id="dataSourceB" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown"> <property name="dataSource"> <bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown"> <property name="transactionManager" ref="jotm"/> <property name="driverName" value="${jdbc2.driver}"/> <property name="url" value="${jdbc2.url}"/> </bean> </property> <property name="user" value="${jdbc2.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- 事务切面配置 --> <aop:config> <aop:pointcut id="serviceOperation" expression="execution(* *..servi1ce*..*(..))"/> <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/> </aop:config> <!-- 通知配置 --> <tx:advice id="txAdvice" transaction-manager="myJtaManager"> <tx:attributes> <tx:method name="delete*" rollback-for="Exception"/> <tx:method name="save*" rollback-for="Exception"/> <tx:method name="update*" rollback-for="Exception"/> <tx:method name="*" read-only="true" rollback-for="Exception"/> </tx:attributes> </tx:advice ...... ...... ......
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值