Distributed Transaction Sample Application

Table Of Contents 

Overview of the Sample Application 

Back To Top

A distributed transaction, sometimes referred to as a global transaction, is a set of two or more related transactions that must be managed in a co-ordinated way. The transactions that constitute a distributed transaction might be in the same database, but more typically are in different databases and often in different locations. Each individual transaction of a distributed transaction is referred to as a transaction branch.

Support for distributed transactions demands a JDBC driver to support the standard two-phase commit protocol used by the Java Transaction API (JTA).

Working of the Sample application

To demonstrate Distributed Transactions Support, the scenario used by this sample application is described below.

The sample application uses two database users, say, TRAVEL and GLOBAL. These users may be on two different database instances or in the same database instance. You can change the username in Connection.properties file found under the top level directory, to match your database users. Look into Description of Sample Files section for folder and file details.

The user schema has two tables: OTN_COUNTRIES which stores list of countries and its details; OTN_EXCHANGE_RATES which keeps track of currency exchange rates between any two countries stored in the OTN_COUNTRIES table. OTN_EXCHANGE_RATES exists in both user schemas.

The sample application implements a servlet which allows the user to update exchange rates between two different countries. As the table OTN_EXCHANGE_RATES exists in two different users in two different database instances, the updation of Exchange Rates forms a distributed transaction. In short, this means either the new rates should get reflected in both the tables or not at all.

When the servlet is loaded and invoked, it creates two separate connection pools. First connection pool corresponds to TRAVEL user transaction branch whereas second connection pool corresponds to GLOBAL user transaction branch. These connection pools are used by the servlet to get database connections and for further processing. The status and errors, if any, will be displayed in the standard output. When the servlet gets a request from the user it will return a page with all the Home Countries in one table and Destination Countries in another table. It gets the connection from the available pool to connect to the database. The user has to select a Home Country and a Destination Country and can view the current Exchange rate or update the Exchange rate.

Here is the code sample for using Transaction APIs. You can find more details of the code in DistributedTransactionServlet.java file under src/oracle/otnsamples/jdbc/dtran folder. Look into Description of Sample Files section for folder and file details.

  private void updateTables(int homeID,int destinationID,float exchangeRate) {
    Connection connectionTravel = null; // Connection to TRAVEL user

    Connection connectionGlobal = null; // Connection to GLOBAL user
    try {
      // Get the database connection from Connection Pool
      connectionTravel = xaConnectionTravel.getConnection();
      connectionGlobal = xaConnectionGlobal.getConnection();

      // Get the Transaction Resources
      XAResource xaResourceTravel = xaConnectionTravel.getXAResource();
      XAResource xaResourceGlobal = xaConnectionGlobal.getXAResource();

      // Create the Transaction IDs
      Xid xidTravel = createXid(1);
      Xid xidGlobal = createXid(2);

      // Start transaction

      xaResourceTravel.start (xidTravel, XAResource.TMNOFLAGS);
      xaResourceGlobal.start (xidGlobal, XAResource.TMNOFLAGS);

      // Create Statements for updating
      Statement stmtTravel = connectionTravel.createStatement();
      Statement stmtGlobal = connectionGlobal.createStatement();
      
      // Execute the Update Statements
      int no = stmtTravel.executeUpdate("UPDATE otn_exchange_rates SET rate="+exchangeRate+
           " WHERE home_con_id="+homeID+" AND new_con_id=" + destinationID);

      no = stmtGlobal.executeUpdate("UPDATE otn_exchange_rates SET rate="+
           exchangeRate+" WHERE home_con_id="+homeID+" AND new_con_id="
           + destinationID);

      // Suspend the transactions

      xaResourceTravel.end(xidTravel, XAResource.TMSUCCESS);
      xaResourceGlobal.end(xidGlobal, XAResource.TMSUCCESS);

      // Prepare the Resource Managers
      int prepareGlobal =  xaResourceGlobal.prepare (xidGlobal);
      int prepareTravel =  xaResourceTravel.prepare (xidTravel);

      boolean doCommit = true; // Boolean to check whether to commit or not

      // If both the branches are to the same Resource Manager, oracle does some
      // optimization. All but one branch return XA_RDONLY. Only one branch will
      // return XA_OK or failure. Commit or Rollback has to be called on this
      // branch only accordingly.
      if (!((prepareTravel == XAResource.XA_OK)||(prepareTravel==XAResource.XA_RDONLY)))
        doCommit = false;

      if (!((prepareGlobal == XAResource.XA_OK)||(prepareGlobal==XAResource.XA_RDONLY)))

        doCommit = false;

      if (prepareTravel == XAResource.XA_OK)
        if (doCommit)
          xaResourceTravel.commit(xidTravel, false);
        else
          xaResourceTravel.rollback(xidTravel);

      if (prepareGlobal == XAResource.XA_OK)
        if (doCommit)
          xaResourceGlobal.commit(xidGlobal, false);
        else
          xaResourceGlobal.rollback(xidGlobal);

      // Close the Statements
      stmtTravel.close();
      stmtGlobal.close();


    } catch(SQLException ex) { // Catch SQL Errors
        ......
    } catch (XAException xae) { // Catch Transaction Exception
        .....
    } finally {   // return the connection objects to the pool
      if (connectionTravel != null)
        try {
          connectionTravel.close();
        } catch(SQLException e) { // Catch SQL Errors
            ......
        }
      if (connectionGlobal != null)
        try {
          connectionGlobal.close();
        } catch(SQLException e) { // Catch SQL Errors
            ......
        }
    }
  }


  /**
   * This method returns a Transaction ID for the Transaction. The  transaction
   * ID contains 2 parts, a global Transaction ID which is set to 9 in this
   * method and a Branch ID that is unique to each branch which is set to the
   * value passed as parameter.
   */
  public static Xid createXid(int pbID) throws XAException {
    byte[] gID = new byte[1];  // Global ID
    gID[0]     = (byte) 9;     // Set Global Id to 9
    byte[] bID = new byte[1];  // Branch ID
    bID[0]     = (byte) pbID; // Set branch ID to the parameter passed

    byte[] globalID = new byte[64];
    byte[] branchID = new byte[64];

    // Copy the Global ID and branch ID to a 64 bit string
    System.arraycopy (gID, 0, globalID, 0, 1);
    System.arraycopy (bID, 0, branchID, 0, 1);


    // Call OracleXid() to generate the Xid
    Xid xid = new OracleXid(0x1234, globalID, branchID);

    // Return the Transaction ID
    return xid;
  }


Required Software

Back To Top
  • Oracle9i JDeveloper ( Note: Oracle9i JDeveloper is Oracle's Visual Java Development Tool and can be downloaded from here )
    or
    JDK1.2.x or above This can be downloaded from here.
  • Oracle9i Database or higher running SQL*Net TCP/IP listener. This can be downloaded from here.
  • Oracle9i JDBC Driver. This can be downloaded from here.
  • Oracle9i Containers for J2EE - OC4J Release 9.0.2. This can be downloaded from here.
  • Ant project build tool. This can be downloaded from here.

Notations Used

Notation
Description
<OC4J_HOME>
points to the directory where oc4j is installed . For example, D:\oc4j
<JAVA_HOME>
points to the directory where JDK1.2 or higher is installed. For example, D:\jdk1.3.1
<HOST_NAME>
points to the hostname name where oc4j is running. For example, incq207a.idc.oracle.com
<UID>
is the oc4j admin username; default is: admin
<ADMIN_PASSWORD>
Password of oc4j admin user.
<PORT>
Port number where OC4J is running, default is: 8888
<ORACLE_HOME>
points to the directory where Oracle9i database is installed. For example, d:\oracle9i
<JDEV_HOME>
points to the directory where Oracle9i JDeveloper is installed. For example: d:\Jdev9i

Application Set-up and Configuration

Back To Top
  • Unjar the provided DistributedTransaction.jar using the following command. 

  • > jar xvf DistributedTransaction.jar

    Note: You will find jar.exe in JDK_HOME\bin. Ensure JDK_HOME\bin is present in your system path. 
    (JDK_HOME is the root directory of the JDKx.x installation). This creates a folder DistributedTransaction with all the source files.

  • Edit DistributedTransaction/Connection.properties file in your favorite editor. The application uses two usernames and related database details. Provide these values by changing the HostName(n),Port(n),SID(n),UserName(n) and 
  • Password(n) to connect to your own database instances where n is either 1 or 2 mentioned below.
HostName1 = incq212e.idc.oracle.com
SID1 = otn9i
Port1 = 1521
UserName1 = travel
Password1 = travel

HostName2 = insn104a.idc.oracle.com
SID2 = ora9idb
Port2 = 1522
UserName2 = global
Password2 = global

Database Set-up 

Back To Top

The application requires 2 users who could be in the same database or in two different databases. Depending on the credentials provided in Connection.properties file , UserName1, for example 'travel' requires two tables viz.. OTN_COUNTRIES and OTN_EXCHANGE_RATES. UserName2, for example 'global' requires only the common table OTN_EXCHANGE_RATES.

Run the SQL Script file DistributedTransaction
.sql to create the database tables and records required by the application. Look into Description of Sample Files section for folder and file details of the SQL file.
For example: SQL>@D:\DistributedTransaction\config\DistributedTransaction.sql

Variables prompted for values when SQL script is run are:

username1 = username used in Connection.properties file corresponding to UserName1.
password1 = password used in Connection.properties file corresponding to Password1.
tnsname1 = tnsname for the database corresponding to HostName1 in Connection.properties.
username2 = username used in Connection.properties file corresponding to UserName2.
password2 = password used in Connection.properties file corresponding to Password2.
tnsname2 = tnsname for the database corresponding to HostName2 in Connection.properties.

Running the Application 

Back To Top

This sample application can be run in 2 different ways listed below.

From Oracle9i JDeveloper

  • Open Oracle9i JDeveloper and use File/Open option to select the DistributedTransaction.jws from the DistributedTransaction directory.
  • Next, select Project/DistributedTransaction.jpr from main menu.
  • Now, select Run/Run DistributedTransaction.jpr from main menu to run the application.

From Stand alone OC4J:

The application can be deployed and run from stand alone OC4J:

On Windows:

This section will describe steps to run the application from Windows NT. The sample can be run either manually or using a script file .

Deploy and run application using batch file: run.bat provided:

By setting few environment variables, the sample application could be deployed by just executing the batch file: run.bat from the command prompt, from DistributedTransaction directory. Environmental variables like JAVA_HOME, OC4J_HOME, HOST_NAME, ADMIN_PASSWORD have to be set before running run.bat file. Look at Notations section for more details on these variables.

Note: Make sure that OC4J is already running.

Example:

D:\DistributedTransaction> set OC4J_HOME=d:\oc4j
D:\DistributedTransaction> set ANT_HOME=d:\ant\jarkarta-ant-1.4.1
D:\DistributedTransaction> set JAVA_HOME=d:\jdk1.3.1
D:\DistributedTransaction> set HOST_NAME=incq207a.idc.oracle.com
D:\DistributedTransaction> set ADMIN_PASSWORD=welcome
D:\DistributedTransaction> run

Access the application using the following url from any browser:
http://<HOST_NAME>:<PORT>/dtrans/DistributedTransactionServlet

Example: http://incq207a.idc.oracle.com:8888/dtrans/DistributedTransactionServlet

Run application manually from Windows:

  • Step 1: Set the following environmental variables:
    • PATH pointing to:
      • the directory where JDK 1.2 or higher is installed.
      • the directory where the project build tool ant is installed.
        Example:
        D:\DistributedTransaction> set PATH=d:\jdk1.3.1\bin;d:\ant\jakarta-ant-1.4.1\bin;%PATH%
    • OC4J_HOME pointing to the directory where oc4j is installed. See Notations for more details.
      Example:
      D:\DistributedTransaction> set OC4J_HOME=d:\oc4j
  • Step 2: From the directory where sample is extracted (example: D:\DistributedTransaction), run the ant utility.

    Example: D:\DistributedTransaction> ant
    This will create dtrans.war and transaction.ear files.

  • Step 3: Start OC4J from <oc4j_home>\j2ee\home directory.

    Example: D:\oc4j\j2ee\home> java -jar oc4j.jar

  • Step 4: From the directory where sample is extracted (example: D:\DistributedTransaction ), deploy the ear files.

    java -jar <OC4J_HOME>\j2ee\home\admin.jar ormi:\\<HOST_NAME> <UID> <ADMIN_PASSWORD> -deploy -file transaction.ear -deploymentName transaction

    Example: D:\oc4j\j2ee\home> java -jar d:\oc4j\j2ee\home\admin.jar ormi://incq207a.idc.oracle.com admin welcome -deploy -file transaction.ear -deploymentName transaction

  • Step 5: Bind the web application to a context root using from the same directory as above step 4.

    java -jar <OC4J_HOME>\j2ee\home\admin.jar ormi://<HOST_NAME> <UID><ADMIN_PASSWORD> -bindWebApp transaction dtrans http-web-site dtrans

    Example: D:\oc4j\j2ee\home>java -jar d:\oc4j\j2ee\home\admin.jar ormi://incq207a.idc.oracle.com admin welcome -bindWebApp transaction dtrans http-web-site dtrans

  • Step 6: Access the application using the following url from any browser:

    http://<HOST_NAME>:<PORT>/dtrans/DistributedTransactionServlet

    Example: http://incq207a.idc.oracle.com:8888/dtrans/DistributedTransactionServlet

On Linux:

This section will describe steps to run the application from console using JDK on Red Hat Linux Advanced Server Release 2.1. The sample can be run either manually or using a script file .

Deploy and run application using script file: run.sh provided:

By setting few environment variables, the sample application could be deployed by just executing the batch file: run.sh from the command prompt, from DistributedTransaction directory. User will be prompted to enter value for the environmental variables required to run the script.

Note: Make sure that OC4J is already running.

  • Go to DistributedTransaction directory and from the $ prompt use the command below to give execute permission to the file.
    $chmod 777 run.sh
  • Now run the file:
    $run.sh

    Access the application using the following url from any browser:
    http://<HOST_NAME>:<PORT>/dtrans/DistributedTransactionServlet

    Example: http://incq207a.idc.oracle.com:8888/dtrans/DistributedTransactionServlet

Running the application manually:

  • Step 1: Set the following environmental variables:
    • PATH pointing to:
      • the directory where JDK 1.2 or higher is installed.
      • the directory where the project build tool ant is installed.
        Example:
        $ export PATH=/home1/java/jdk1.3.1/bin:/home1/ant/bin:$PATH
    • OC4J_HOME pointing to the directory where oc4j is installed. See Notations for more details.
      Example:
      $ export OC4J_HOME=/home1/oc4j
    • JAVA_HOME pointing to the directory where JDK 1.2 or higher is installed.
      Example:
      $ export JAVA_HOME=/home1/java/jdk1.3.1

  • Step 2: From the directory where sample is extracted (example /home1/jdbc/DistributedTransaction), run the ant utility.

    Example: $ ant
    This will create dtrans.war and transaction.ear files.

  • Step 3: Start OC4J from <oc4j_home>/j2ee/home directory.

    Example: $ java -jar oc4j.jar

  • Step 4: From the directory where sample is extracted (example /home1/jdbc/DistributedTransaction), deploy the ear files.

    java -jar <OC4J_HOME>/j2ee/home/admin.jar ormi://<HOST_NAME> <UID> <ADMIN_PASSWORD> -deploy -file transaction.ear -deploymentName transaction

    Example: $java -jar /home1/oc4j/j2ee/home/admin.jar ormi://incq207a.idc.oracle.com admin welcome -deploy -file transaction.ear -deploymentName transaction

  • Step 5: Bind the web application to a context root using from the same directory as above step 4.

    java -jar <OC4J_HOME>/j2ee/home/admin.jar ormi://<HOST_NAME> <UID><ADMIN_PASSWORD> -bindWebApp transaction dtrans http-web-site dtrans

    Example: $java -jar /home1/oc4j/j2ee/home/admin.jar ormi://incq207a.idc.oracle.com admin welcome -bindWebApp transaction dtrans http-web-site dtrans

  • Step 6: Access the application using the following url from any browser:

    http://<HOST_NAME>:<PORT>/dtrans/DistributedTransactionServlet

    Example: http://incq207a.idc.oracle.com:8888/dtrans/DistributedTransactionServlet

Description of Sample Files 

Back To Top
The directory structure of the deliverable DistributedTransaction.jar will be as shown below. DistributedTransaction is the top level directory.

Directory
Files
Description
DistributedTransaction
DistributedTransaction.jws
The Oracle9i JDeveloper workspace file.
DistributedTransaction.jpr
The Oracle9i JDeveloper project file.
Connection.properties This file has the details of the database connection parameters.
build.xml Project build file used by ANT tool to create transaction.ear file which is deployed to stand alone OC4J.
run.bat The batch file to compile and deploy the sample in Windows environment.
run.sh The shell script to compile and deploy the sample in Linux environment.
DistributedTransaction\doc
Readme.html This file.
DistributedTransaction\config
DistributedTransaction.sql This is the SQL script file to create the required tables in the database.
DistributedTransaction\META-INF
application.xml Application level J2EE deployment descriptor.
DistributedTransaction\WEB-INF
web.xml Deployment descriptor for the web application.
DistributedTransaction\src\oracle\otnsamples\jdbc\dtran DistributedTransactionServlet.java
The servlet source file for the sample.
DistributedTransactionHTML.java This class contains static methods, which generate HTML pages for the Distributed Transaction Sample.

Troubleshooting  

Back To Top

From Oracle9i JDeveloper, if the update of the tables does not happen, follow the steps below to re-configure Oracle9i JDeveloper to use classes12.zip shipped with Oracle9i database.

  • Take a backup of the present Oracle9i JDBC Driver (classes12dms.jar) by renaming it as classes12dms_backup.jar
  • Copy the classes12.jar from the <ORACLE_HOME>/jdbc/lib directory into <JDEV_HOME>/jdbc/lib
  • Rename the copied classes12.jar as classes12dms.jar to complete the configuration.
  • Stop the embedded OC4J and re-run the application.

Please enter your comments about this sample inthe OTN SampleCode Discussion Forum.
E-mail this page
Printer View Printer View
Oracle Is The Information Company About Oracle | Oracle RSS Feeds | Careers | Contact Us | Site Maps | Legal Notices | Terms of Use | Privacy