专注Java教育14年 全国咨询/投诉热线:400-8080-105
动力节点LOGO图
始于2009,口口相传的Java黄埔军校
首页 hot资讯 使用JTA方法的分布式事务示例

使用JTA方法的分布式事务示例

更新时间:2021-08-17 10:49:07 来源:动力节点 浏览902次

分布式事务通常涉及到同一数据源或不同数据源的多个连接,其中可能包括来自不同制造商的数据源。

演示分布式事务的最佳方式是将它们与本地事务进行对比。对于本地事务,JDBC应用程序对数据库进行永久性更改,并通过以下方式之一指示工作单元的结束:

通过在执行一个或多个SQL语句后调用Connection.commit或Connection.rollback方法

通过在应用程序开始时调用Connection.setAutoCommit(true)方法在每个SQL语句之后提交更改

图 1概述了执行本地事务的代码。

图 1. 本地事务示例

con1.setAutoCommit(false);  // Set autocommit off
// execute some SQL
…
con1.commit();              // Commit the transaction
// execute some more SQL
…
con1.rollback();            // Roll back the transaction
con1.setAutoCommit(true);   // Enable commit after every SQL statement
…
// Execute some more SQL, which is automatically committed after
// every SQL statement.

相反,参与分布式事务的应用程序不能在分布式事务中调用Connection.commit、Connection.rollback或Connection.setAutoCommit(true)方法。对于分布式事务,Connection.commit或Connection.rollback方法不指示事务边界。相反,您的应用程序让应用程序服务器管理事务边界。

图 2演示了一个使用分布式事务的应用程序。在示例中的代码运行时,应用程序服务器也在执行属于同一分布式事务的其他EJB。当所有EJB都调用utx.commit() 时,整个分布式事务由应用程序服务器提交。如果任何EJB不成功,应用程序服务器将回滚与分布式事务相关联的所有EJB所做的所有工作。

图 2. 应用服务器下的分布式事务示例

javax.transaction.UserTransaction utx;
// Use the begin method on a UserTransaction object to indicate
// the beginning of a distributed transaction.
utx.begin();
…
// Execute some SQL with one Connection object.
// Do not call Connection methods commit or rollback.
…
// Use the commit method on the UserTransaction object to
// drive all transaction branches to commit and indicate
// the end of the distributed transaction.
utx.commit();
…

图 3说明了一个使用JTA方法执行分布式事务的程序。该程序充当事务管理器和事务应用程序。到两个不同数据源的两个连接在单个分布式事务下执行SQL工作。

图 3. 使用JTA的分布式事务示例

class XASample
{
  javax.sql.XADataSource xaDS1;
  javax.sql.XADataSource xaDS2;
  javax.sql.XAConnection xaconn1;
  javax.sql.XAConnection xaconn2;
  javax.transaction.xa.XAResource xares1;
  javax.transaction.xa.XAResource xares2;
  java.sql.Connection conn1;
  java.sql.Connection conn2;
  public static void main (String args []) throws java.sql.SQLException
  {
    XASample xat = new XASample();
    xat.runThis(args);
  }
  // As the transaction manager, this program supplies the global 
  // transaction ID and the branch qualifier. The global 
  // transaction ID and the branch qualifier must not be 
  // equal to each other, and the combination must be unique for 
  // this transaction manager.
  public void runThis(String[] args)
  {
    byte[] gtrid = new byte[] { 0x44, 0x11, 0x55, 0x66 };
    byte[] bqual = new byte[] { 0x00, 0x22, 0x00 };
    int rc1 = 0;
    int rc2 = 0;
    try
    {
      javax.naming.InitialContext context = new javax.naming.InitialContext();
      /*
        * Note that javax.sql.XADataSource is used instead of a specific
        * driver implementation such as com.ibm.db2.jcc.DB2XADataSource.
        */
      xaDS1 = (javax.sql.XADataSource)context.lookup("checkingAccounts");
      xaDS2 = (javax.sql.XADataSource)context.lookup("savingsAccounts");
      // The XADatasource contains the user ID and password.
      // Get the XAConnection object from each XADataSource
      xaconn1 = xaDS1.getXAConnection();
      xaconn2 = xaDS2.getXAConnection();
      // Get the java.sql.Connection object from each XAConnection
      conn1 = xaconn1.getConnection();
      conn2 = xaconn2.getConnection();
      // Get the XAResource object from each XAConnection
      xares1 = xaconn1.getXAResource();
      xares2 = xaconn2.getXAResource();      
      // Create the Xid object for this distributed transaction.
      // This example uses the com.ibm.db2.jcc.DB2Xid implementation
      // of the Xid interface. This Xid can be used with any JDBC driver
      // that supports JTA.
      javax.transaction.xa.Xid xid1 =
                               new com.ibm.db2.jcc.DB2Xid(100, gtrid, bqual);
      // Start the distributed transaction on the two connections.
      // The two connections do NOT need to be started and ended together.
      // They might be done in different threads, along with their SQL operations.
      xares1.start(xid1, javax.transaction.xa.XAResource.TMNOFLAGS);
      xares2.start(xid1, javax.transaction.xa.XAResource.TMNOFLAGS);
…
      // Do the SQL operations on connection 1.
      // Do the SQL operations on connection 2.
…
      // Now end the distributed transaction on the two connections.
      xares1.end(xid1, javax.transaction.xa.XAResource.TMSUCCESS);
      xares2.end(xid1, javax.transaction.xa.XAResource.TMSUCCESS);
      // If connection 2 work had been done in another thread,
      // a thread.join() call would be needed here to wait until the
      // connection 2 work is done.
      try
      { // Now prepare both branches of the distributed transaction.
        // Both branches must prepare successfully before changes
        // can be committed.
        // If the distributed transaction fails, an XAException is thrown.
        rc1 = xares1.prepare(xid1);
        if(rc1 == javax.transaction.xa.XAResource.XA_OK)
        { // Prepare was successful. Prepare the second connection.
          rc2 = xares2.prepare(xid1);
          if(rc2 == javax.transaction.xa.XAResource.XA_OK)
          { // Both connections prepared successfully and neither was read-only.
            xares1.commit(xid1, false);
            xares2.commit(xid1, false);
          }
          else if(rc2 == javax.transaction.xa.XAException.XA_RDONLY)
          { // The second connection is read-only, so just commit the 
            // first connection.
            xares1.commit(xid1, false);
          }
        }
        else if(rc1 == javax.transaction.xa.XAException.XA_RDONLY)
        { // SQL for the first connection is read-only (such as a SELECT).
          // The prepare committed it. Prepare the second connection.
          rc2 = xares2.prepare(xid1);
          if(rc2 == javax.transaction.xa.XAResource.XA_OK)
          { // The first connection is read-only but the second is not.
            // Commit the second connection.
            xares2.commit(xid1, false);
          }
          else if(rc2 == javax.transaction.xa.XAException.XA_RDONLY)
          { // Both connections are read-only, and both already committed,
            // so there is nothing more to do.
          }
        }
      }      catch (javax.transaction.xa.XAException xae)
      { // Distributed transaction failed, so roll it back.
        // Report XAException on prepare/commit.
        System.out.println("Distributed transaction prepare/commit failed. " +
                            "Rolling it back.");
        System.out.println("XAException error code = " + xae.errorCode);
        System.out.println("XAException message = " + xae.getMessage());
        xae.printStackTrace();
        try
        {
          xares1.rollback(xid1);
        }
        catch (javax.transaction.xa.XAException xae1)
        { // Report failure of rollback.
          System.out.println("distributed Transaction rollback xares1 failed");
          System.out.println("XAException error code = " + xae1.errorCode);
          System.out.println("XAException message = " + xae1.getMessage());
        }
        try
        {
          xares2.rollback(xid1);
        }
        catch (javax.transaction.xa.XAException xae2)
        { // Report failure of rollback.
          System.out.println("distributed Transaction rollback xares2 failed");
          System.out.println("XAException error code = " + xae2.errorCode);
          System.out.println("XAException message = " + xae2.getMessage());
        }
      }
      try
      {
        conn1.close();
        xaconn1.close();
      }
      catch (Exception e)
      {
        System.out.println("Failed to close connection 1: " + e.toString());
        e.printStackTrace();
      }
      try
      {
        conn2.close();
        xaconn2.close();
      }
      catch (Exception e)
      {
        System.out.println("Failed to close connection 2: " + e.toString());
        e.printStackTrace();
      }
    }
    catch (java.sql.SQLException sqe)
    {
      System.out.println("SQLException caught: " + sqe.getMessage());
      sqe.printStackTrace();
    }
    catch (javax.transaction.xa.XAException xae)
    {
      System.out.println("XA error is " + xae.getMessage());
      xae.printStackTrace();
    }
    catch (javax.naming.NamingException nme)
    {
      System.out.println(" Naming Exception: " + nme.getMessage());
    }
  }
}

建议:为了获得更好的性能,请先完成一个分布式事务,然后再启动另一个分布式或本地事务。

以上就是动力节点小编介绍的"使用JTA方法的分布式事务示例",希望对大家有帮助,想了解更多可查看Java分布式应用教程。动力节点在线学习教程,针对没有任何Java基础的读者学习,让你从入门到精通,主要介绍了一些Java基础的核心知识,让同学们更好更方便的学习和了解Java编程,感兴趣的同学可以关注一下。

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>