首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > 其他数据库 >

JTA事宜和JDBC事务

2012-07-15 
JTA事务和JDBC事务一般情况下,J2EE应用服务器支持JDBC事务、JTA事务、容器管理事务。这里讨论JTA和JDBC事务的

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 …”); //数据库更新操作1stmt.executeUpdate(“insert into table …”); //数据库更新操作2       conn.commit(); //事务提交     }catch(Exception ex) {             ex.printStackTrace();         try {          conn.rollback(); //操作不成功则回滚          }catch(Exception e) {e.printStackTrace();           }}


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

JTA事务

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

热点排行