`

JMS MDB 与 XA 事务-001

 
阅读更多
什么是JTA

   Java事务API(JTA;Java Transaction API)和它的同胞Java事务服务JTS(Java Transaction Service),为J2EE平台提供了分布式事务服务。

   一个分布式事务(distributed transaction)包括一个事务管理器(transaction manager)和一个或多个资源管理器(resource manager)。一个资源管理器(resource manager)是任意类型的持久化数据存储。事务管理器(transaction manager)承担着所有事务参与单元者的相互通讯的责任。下图显示了事务管理器和资源管理的间的关系。

  JTA事务比JDBC事务更强大。一个JTA事务可以有多个参与者,而一个JDBC事务则被限定在一个单一的数据库连接。下列任一个Java平台的组件都可以参与到一个JTA事务中:
  .JDBC连接
  .JDO PersistenceManager 对象
  .JMS 队列
  .JMS 主题
  .企业JavaBeans(EJB)
  .一个用J2EE Connector Architecture 规范编译的资源分配器。
使用JTA的事务划分
  要用JTA来划分一个事务,应用程序调用javax.transaction.UserTransaction接口中的方法。示例4显示了一个典型的JNDI搜索的UseTransaction对象。
  import javax.transaction.*;
  import javax.naming.*;
  // ...
  InitialContext ctx = new InitialContext();
  Object txObj = ctx.lookup(";java:comp/UserTransaction";);
  UserTransaction utx = (UserTransaction) txObj; 
  应用程序有了UserTransaction对象的引用之后,就可以象示例5那样来起动事务。
   utx.begin();
  // ...
  DataSource ds = obtainXADataSource();
  Connection conn = ds.getConnection();
  pstmt = conn.prepareStatement(";UPDATE MOVIES ...";);
  pstmt.setString(1, ";Spinal Tap";);
  pstmt.executeUpdate();
  // ...
  utx.commit();
  // ...
 当应用程序调用commit()时,事务管理器使用两段提交协议来结束事务。JTA事务控制的方法:
  .javax.transaction.UserTransaction接口提供
使用JTA和JDBC
  应用程序调用begin()来起动事务,即可调用commit()也可以调用rollback()来结束事务。
  开发人员经常使用JDBC来作为DAO类中的底层数据操作。如果计划使用JTA来划分事务,你将需要一个实现了javax.sql.XADataSource,javax.sql.XAConnection和javax.sql.XAResource接口JDBC的驱动。实现了这些接口的驱动将有能力参与到JTA事务中。一个XADataSource对象是一个XAConnection对象的工厂。XAConnections是参与到JTA事务中的连接。
  你需要使用应用程序服务器管理工具来建立XADataSource对象。对于特殊的指令请参考应用程序服务器文档和JDBC驱动文档。
  J2EE应用程序使用JNDI来查找数据源。一旦应用程序有了一个数据源对象的引用,这会调用javax.sql.DataSource.getConnection()来获得数据库的连接。
  XA连接区别于非XA连接。要记住的是XA连接是一个JTA事务中的参与者。这就意味着XA连接不支持JDBC的自动提交特性。也就是说应用程序不必在XA连接上调用java.sql.Connection.commit()或java.sql.Connection.rollback()。相反,应用程序应该使用UserTransaction.begin()、UserTransaction.commit()和UserTransaction.rollback().
  选择最好的方法
  我们已经讨论了JDBC和JTA是怎样划分事务的。每一种方法都有它的优点,因此你需要决定为你的应用程序选择一个最适应的方法。在我们团队许多最近的对于事务划分的项目中使用JDBC API来创建DAO类。这DAO类总结如下:
  .事务划分代码被嵌入到DAO类内部
  .DAO类使用JDBC API来进行事务划分
  .调用者没有划分事务的方法
  .事务范围被限定在一个单一的JDBC连接
  JDBC事务对复杂的企业应用程序不总是有效的。如果你的事务将跨越多个DAO对象或多个数据库,那么下面的实现策略可能会更恰当:
  .用JTA对事务进行划分
  .事务划分代码被DAO分开
  .调用者承担划分事务的责任
  .DAO参与一个全局的事务中
  JDBC方法由于它的简易性而具有吸引力,JTA方法提供了更多灵活性。你选择什么样的实现将依赖于你的应用程序的特定需求。
  JTA(Java Transaction API) 为 J2EE 平台提供了分布式事务服务。
  要用 JTA 进行事务界定,应用程序要调用 javax.transaction.UserTransaction 接口中的方法。例如:
  utx.begin();
  // ...
  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 连本地都支持不好,更别说分布事务了。
  MySql 在5.0的版本后增加了对xa的支持
JTA方式的实现过程
  用XADataSource产生的XAConnection它扩展了一个getXAResource()方法,事务通过这个方法把它加入到事务容器中进行管理.对于调用者来说,根本看不到事务是如何管理的,你只要声明开始事务,告诉容器我下面的操作要求事务参与了,最后告诉事务说到这儿可以提交或回滚了,别的都是暗箱操作。
  在使用JTA之前,你必须首先实现一个Xid类用来标识事务(在普通情况下这将由事务管理程序来处理)。Xid包含三个元素:formatID、gtrid(全局事务标识符)和bqual(分支修饰词标识符)。
  下面的例子说明Xid的实现:
  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;
  }
  }
  其次,你需要创建一个你要使用的数据库的数据源:
  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?这个例子是用“两步提交协议”来提交一个事务分支:
  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[], new byte[]);
  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最终的实现代码。

例2?这个例子,与例1相似,说明了一个返回过程:

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.rollback(xid);
}

  例3?这个例子说明一个分布式事务分支如何中止,让相同的连接做本地事务处理,以及它们稍后该如何继续这个分支。 分布式事务的两步提交作用不影响本地事务。

xid = new MyXid(100, new byte[]{0x01}, new byte[]{0x02});
xaRes.start(xid, XAResource.TMNOFLAGS);
stmt.executeUpdate("insert into test_table values (100)");
xaRes.end(xid, XAResource.TMSUSPEND);
∥这个更新在事务范围之外完成,所以它不受XA返回影响。

stmt.executeUpdate("insert into test_table2 values (111)");
xaRes.start(xid, XAResource.TMRESUME);
stmt.executeUpdate("insert into test_table values (200)");
xaRes.end(xid, XAResource.TMSUCCESS);
ret = xaRes.prepare(xid);

if (ret == XAResource.XA_OK) {

xaRes.rollback(xid);

}

  例4?这个例子说明一个XA资源如何分担不同的事务。 创建了两个事务分支,但是它们不属于相同的分布式事务。 JTA允许XA资源在第一个分支上做一个两步提交,虽然这个资源仍然与第二个分支相关联。

xid1 = new MyXid(100, new byte[]{0x01}, new byte[]{0x02});
xid2 = new MyXid(100, new byte[]{0x11}, new byte[]{0x22});
xaRes.start(xid1, XAResource.TMNOFLAGS);
stmt.executeUpdate("insert into test_table1 values (100)");
xaRes.end(xid1, XAResource.TMSUCCESS);
xaRes.start(xid2, XAResource.TMNOFLAGS);
ret = xaRes.prepare(xid1);
if (ret == XAResource.XA_OK) {
 xaRes.commit(xid2, false);
}
stmt.executeUpdate("insert into test_table2 values (200)");
xaRes.end(xid2, XAResource.TMSUCCESS);
ret = xaRes.prepare(xid2);
if (ret == XAResource.XA_OK) {
 xaRes.rollback(xid2);
}

  例5?这个例子说明不同的连接上的事务分支如何连接成为一个单独的分支,如果它们连接到相同的资源管理程序。这个特点改善了分布式事务的效率,因为它减少了两步提交处理的数目。两个连接到数据库服务器上的XA将被创建。每个连接创建它自己的XA资源,正规的JDBC连接和语句。在第二个XA资源开始一个事务分支之前,它将察看是否使用和第一个XA资源使用的是同一个资源管理程序。如果这是实例,它将加入在第一个XA连接上创建的第一个分支,而不是创建一个新的分支。 稍后,这个事务分支使用XA资源来准备和提交。

xaDS = getDataSource();
xaCon1 = xaDS.getXAConnection("jdbc_user", "jdbc_password");
xaRes1 = xaCon1.getXAResource();
con1 = xaCon1.getConnection();
stmt1 = con1.createStatement();

xid1 = new MyXid(100, new byte[]{0x01}, new byte[]{0x02});
xaRes1.start(xid1, XAResource.TMNOFLAGS);
stmt1.executeUpdate("insert into test_table1 values (100)");
xaRes1.end(xid, XAResource.TMSUCCESS);
xaCon2 = xaDS.getXAConnection("jdbc_user", "jdbc_password");
xaRes2 = xaCon1.getXAResource();
con2 = xaCon1.getConnection();
stmt2 = con1.createStatement();

if (xaRes2.isSameRM(xaRes1)) {
 xaRes2.start(xid1, XAResource.TMJOIN);
 stmt2.executeUpdate("insert into test_table2 values (100)");
 xaRes2.end(xid1, XAResource.TMSUCCESS);
}
else {
 xid2 = new MyXid(100, new byte[]{0x01}, new byte[]{0x03});
 xaRes2.start(xid2, XAResource.TMNOFLAGS);
 stmt2.executeUpdate("insert into test_table2 values (100)");
 xaRes2.end(xid2, XAResource.TMSUCCESS);
 ret = xaRes2.prepare(xid2);
 if (ret == XAResource.XA_OK) {
  xaRes2.commit(xid2, false);
 }
}
ret = xaRes1.prepare(xid1);
if (ret == XAResource.XA_OK) {
 xaRes1.commit(xid1, false);
}


  例6?这个例子说明在错误恢复的阶段,如何恢复准备好的或者快要完成的事务分支。 它首先试图返回每个分支;如果它失败了,它尝试着让资源管理程序丢掉关于事务的消息。

MyXid[] xids;
xids = xaRes.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN);
for (int i=0; xids!=null && i  try {
  xaRes.rollback(xids[i]);
 }
 catch (XAException ex) {
  try {
   xaRes.forget(xids[i]);
  }
 catch (XAException ex1) {
  System.out.println("rollback/forget failed: " + ex1.errorCode);
 }
}

}
分享到:
评论

相关推荐

    JMS MDB 与 XA 事务-002

    这篇博客"JMS MDB 与 XA 事务-002"可能探讨了如何在Java企业版(Java EE)环境中,通过消息驱动bean(Message-Driven Bean,简称MDB)和XA事务来实现可靠的消息传递和跨多个资源的事务一致性。 MDB是Java EE容器中...

    MDB-RS232专业版串口MDB接口设备测试工具

    MDB-RS232专业版测试工具,可以通过威佛MDB-RS232适配器对MDB纸币器(08H),硬币器(30H),非现金支付1(10H),非现金支付2(60H),USB设备(40H),年龄验证设备(68H)进行综合测试。当然下载测试工具之前需要...

    MDB-Cashless-Test.rar_MDB-Cashless-Test_mdb-rs232_mdb测试工具_vendin

    标题中的“MDB-Cashless-Test.rar_MDB-Cashless-Test_mdb-rs232_mdb测试工具_vendin”提到了几个关键概念,包括MDB协议、非现金支付、RS232-MDB适配器、测试工具以及与自动售货机相关的应用。这些关键词都是IT行业中...

    精彩编程与编程技巧-MDB文件的导出 ---- 使用 DAO...

    ### 知识点详解:使用DAO进行MDB文件的导出 #### 1. MDB文件简介 - **MDB文件**:通常指Microsoft Access数据库文件格式,它用于存储多种数据类型,如表格、查询、窗体、报表等。 - **DAO (Data Access Object)**:...

    Weblogic10_JMS、MDB分布式部署学习

    JMS 是一个标准接口,允许 Java 应用程序与其他应用程序进行消息传递,而 MDB 是 EJB (Enterprise JavaBeans) 的一种类型,它作为消息的消费者,自动响应来自 JMS 队列或主题的消息。 1. JMS 学习总结: - JMS ...

    JMS与MDB介绍

    JMS与MDBMessage Driven Bean(MDB)是Java EE中的一种特殊类型的Enterprise Bean,专门用于处理JMS消息。MDB作为消息的消费者,可以异步地接收和处理消息,极大地简化了后台服务的编程模型。当消息到达队列或主题时...

    MDB: A Memory-Mapped Database and Backend for OpenLDAP

    ### MDB: 内存映射数据库与OpenLDAP后端 #### 概述 本文主要介绍了一种名为MDB(Memory-Mapped Database)的读优化数据库库及其作为OpenLDAP后端的应用。该技术由Howard Chu开发,并在Symas Corp.以及OpenLDAP项目...

    ZX-D30+XY-MDB40A+JDY-33+HC-05

    ZX-D30+XY-MDB40A+JDY-33+HC-05

    MDBootstrap_4.11.0_Pro_4.8.11_Templates_Gulp.rar

    ,MDB-Admin-Dashboard-Templates-Pack_4.8.11,MDB-Blog-Templates-Pack_4.8.11,MDB-ecommerce-Templates-Pack_4.8.11,MDB-Landing-Page-Templates-Pack_4.8.11,MDB-Magazine-Templates-Pack_4.8.11,MDB-Portfolio-...

    MDB 4.3 协议文档 Multi-Drop-Bus-and-Internal-Communication-Protocol

    对于现金支付之外的选项,MDB 4.3特别关注了无现金设备的通信规范,包括状态定义、命令协议、设备命令响应格式以及非响应时间,以确保这些设备能够无缝地与售货机系统集成。 **总结** MDB 4.3协议是自动售货机行业...

    MDB-Pro-4_mdb_MDB-Pro_dayty7_leastbcf.zip

    标题 "MDB-Pro-4_mdb_MDB-Pro_dayty7_leastbcf.zip" 暗示这是一个与MDB-Pro相关的项目,可能是一个软件或系统的版本号,其中“mdb”可能指的是Microsoft Access数据库格式。描述中的内容与标题相同,进一步确认了这...

    MDB-Pro-4_mdb_MDB-Pro_dayty7_leastbcf_源码.zip

    标题 "MDB-Pro-4_mdb_MDB-Pro_dayty7_leastbcf_源码.zip" 提供的信息表明,这是一个关于MDB-Pro项目的源代码压缩包。MDB-Pro可能是某种软件或应用程序的名称,而“dayty7_leastbcf”可能是该版本的一个特定标识符...

    MDB-C-master_mdb_

    综上所述,"MDB-C-master_mdb_"项目是一个使用C或C++语言直接操作MDB数据库的实现,涵盖了数据库编程、内存映射、事务处理、并发控制等多个核心领域,为开发者提供了在C/C++环境中高效操作数据库的能力。通过学习和...

    mdb-vue-ui-kit:Vue 3和Bootstrap 5和Material Design 2.0 UI套件

    MDB 5 Vue Vue 3和Bootstrap 5和Material Design 2.0 UI套件 500多种材料UI组件 超级简单,一分钟安装 详细的文档和多个实际示例 Vue 3 庞大而活跃的社区 MIT许可证-免费供个人和商业使用 受到2000000+开发人员和...

    李腾飞]JMS与MDB简介.pdf

    根据给定的文件信息,我们可以深入探讨JMS(Java消息服务)与MDB(Message-Driven Bean)的关键概念及其在企业级应用中的作用。 ### 基本概念 JMS是Java平台上的消息中间件标准,它允许应用程序组件通过异步通信的...

    广优MDB数据库批量更改 -ASP源码.zip

    ASP源码,压缩包解压密码:www.cqlsoft.com

Global site tag (gtag.js) - Google Analytics