JTA

JTA概述  JTA,即Java Transaction API,译为Java事务API。

  JTA允许应用程序执行分布式事务处理——在两个或多个网络计算机资源上访问并且更新数据。JDBC驱动程序的JTA支持极大地增强了数据访问能力。

编辑本段JTA和JTS

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

  一个分布式事务(distributed transaction)包括一个事务管理器(transaction manager)和一个或多个资源管理器(resource manager)。

  一个资源管理器(resource manager)是任意类型的持久化数据存储。

  事务管理器(transaction manager)承担着所有事务参与单元者的相互通讯的责任。

编辑本段JTA与JDBC

  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 MOⅥES ...";);
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连接区别于非XA连接。要记住的是XA连接是一个JTA事务中的参与者。这就意味着XA连接不支持JDBC的自动提交特性。也就是说应用程序不必在XA连接上调用java.sql.Connection.commit()或java.sql.Connection.rollback()。相反,应用程序应该使用UserTransaction.begin()、UserTransaction.commit()和UserTransaction.rollback().

DAO类总结

  我们已经讨论了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 MOⅥES ...");

  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()方法,事务通过这个方法把它加入到事务容器中进行管理.对于调用者来说,根本看不到事务是如何管理的,你只要声明开始事务,告诉容器我下面的操作要求事务参与了,最后告诉事务说到这儿可以提交或回滚了,别的都是暗箱操作。

首先,实现一个Xid类用来标识事务

  在使用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[]{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();

  }

  因为所有这些例子中的初始化代码相同或者非常相似,仅仅是一些重要的地方的代码由不同。

  例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);

  }

  }

  }

时间: 2024-10-21 21:02:39

JTA的相关文章

oc4j+toplink+spring使用jta外部事务的一点心得

晚上要下班的时候,application team那里使用Tibco EMS做消息集成服务时候出了bug,错误是: java.sql.SQLException: 当全局事务处理处于活动状态时, 无法调用方法 'commit',应该是在全局事务 中使用了本地事务并提交了.帮忙看了一下,它的oc4j, toplink, spring的使用上都存在着一些问题, 并把要注意的地方总结了一下. Jta外部事务,也称为分布式事务,全局事务. oc4j: ·让transaction manager知道reso

Spring集成JOTM的JTA事务管理

Spring中集成JOTM 配置JTA事务: 假如业务中要用到多个数据库,我们希望在业务方法中,当对某一个数据库的数据表进行操作的事务失败并回退(rollback),另外某一个数据库的数据表的操作事务也要回退,但应用一般的事务管理达不到这样的事务管理效果,这就需要实现 JTA 事务管理了. 这里我们在SPring中集成 Object web 的一个开源JTA实现JOTM (可以在http://jotm.objectweb.org下载完整版) 来实现JTA事务管理. 1.将必须的类包放入类路径中:

Spring多数据源分布式事务管理/springmvc+spring+atomikos[jta]+druid+mybatis

项目进行读写分离及分库分表,在一个业务中,在一个事务中处理时候将切换多个数据源,需要保证同一事务多个数据源数据的一致性.此处使用atomikos来实现:最后附源码: 1:spring3.0之后不再支持jtom[jta]了,第三方开源软件atomikos(http://www.atomikos.com/)来实现.  2:org.springframework.transaction.jta.JotmFactoryBean类,spring-tx-2.5.6.jar中有此类,spring-tx-3.0

jta-多数据源配置与JTA事务问题

问题描述 多数据源配置与JTA事务问题 项目中使用两个dataSourc,两个sessionFactory.由于业务变化,需要在项目中切换数据源,单独配置多数据源以及单独配置JTA都能成功,将多数据与JTA整合之后,项目启动总是抛出异常. 异常如下: org.springframework.transaction.IllegalTransactionStateException: Pre-bound JDBC Connection found! HibernateTransactionManag

01_Weblogic课程之概念篇:代理服务器,web服务器,应用程序服务器,JNDI概念,JTA概念,Java消息服务,Java验证和授权(JAAS),Java管理扩展,Web客户机,客户机应用程序

 1 什么是服务器 Weblogic中服务器分为两种,一种是受管服务器,另外一种是管理服务器.   Weblogic课程(Weblogic是Oracle公司的,最开始的是BEA公司的) 一 系统管理 二 开发 三 性能调优   WLS(Weblogic Server)   Weblogic 12c新特性是加入了云支持   2 集群的好处:失败迁移和负载均衡. 3 分布式系统 分布式系统将工作划分到几个独立的模块中. 单个模块出现故障对整个系统的影响较小,这使得分布式系统具有更高的: ----

Spring JTA事务配置JOTM

JTA可以在多个数据库上使用一个事务,weblogic等应用服务器提供了jta数据源的支持,可以直接被使用.但是tomcat本身并不支持这种特性.如果想在tomcat上使用jta就必须使用其它的工具.jotm就是一个独立的可以提供JTA功能的组件. <?xml version="1.0" encoding="UTF-8"?>      <beans xmlns="http://www.springframework.org/schema/

jta-为什么在JMS中使用JTA事务控制全局事务失效

问题描述 为什么在JMS中使用JTA事务控制全局事务失效 package cn.producer; import java.util.Properties; import javax.jms.Connection;import javax.jms.ConnectionFactory;import javax.jms.Destination;import javax.jms.ExceptionListener;import javax.jms.JMSException;import javax.j

SpringMVC+MyBatis+JMS+JTA(分布式事务)

SpringMVC+MyBatis 相信已经是现在企业开发中常用技术了. 因为一些需求,我们需要集成JMS(我使用的是ActiveMQ),大家应该都知道,MQ也可以认为是一个数据源,数据也是数据源.这种情况下,如果我们在一个方法内操作JMS和数据库,我们就需要保证这个方法执行需要满足原子性. 这也就意味这一个问题,我们要多个数据源在同一个事务中.这里不枚举市面上的所有解决方案,其实atomikos JTA 是一个比较不错分布式事务管理器. 当然如果没有使用到JMS,在需要多数据源(也就是需要连接

spring + hibernate +jta 事务不能回滚问题

问题描述 spring 配置文件<bean id="idcJDBC" class="com.atomikos.jdbc.SimpleDataSourceBean"><property name="uniqueResourceName"><value>db_idcbase</value></property><property name="xaDataSourceClass

ejb3.o jta事务问题 大家帮忙看看.

问题描述 persistent.xml文件配置:<persistence-unitname="test"transaction-type="JTA"><jta-data-source>java:/mysqlDS</jta-data-source><class>entity.Person</class><exclude-unlisted-classes>true</exclude-unlis