Distributed Transactions

A distributed transaction, also referred to as global transaction, is a set of one or more transactions that are managed together. Transactions in a distributed transaction may be located in the same database or in different databases. Each transaction is called a transaction branch.

Distributed transactions, an extended API of the JDBC 2.0 standard, are provided either with connection pooling functionality or the XA standard of the X/Open DTP (Distributed Transaction Processing) standards.

A distributed transaction has the following features.

  • An external transaction manager is used to manage its individual transactions. The transaction manager is a software component that implements the Java Transaction API standard. Many vendors provide XA-compatible JTA modules.

  • XA functionality is separated from an application, and used in a middle tier such as an application server.

  • The resource manager normally indicates data or other types of resources. In this chapter, it indicates a database.

Components

The following describes individual functions of XA components.

XADataSource

The concepts and functionality of XADataSources are similar to those of Connection Pool DataSources and other DataSources. In each resource manager (database) used for a distributed transaction, a single XADataSource object exists, and this DataSource creates an XAConnection.

XAConnection

An XAConnection is an extended pooled connection. It is conceptually and functionally similar to a pooled connection. An XAConnection works as a temporary handle for the physical database connection, and a single XAConnection corresponds to a single database session.

XAResource

An XAResource is used by the transaction manager to combine each transaction branch of a distributed transaction. One XAResource object can be obtained from each XAConnection, and they have a 1:1 relationship.

This means that one XAResource object corresponds to one database session. One XAResource objectcan have only a single running transaction branch, but it may also have stopped transactions. Each XAResource object operates in each corresponding session, and performs functions such as start, end, prepare, commit, and rollback.

XID

To identify each transaction branch, an XID (transaction ID) is used, and one XID consists of a transaction branch ID and a distributed transaction ID.


Switching between Global and Local Transactions

In the JDBC 3.0 standard, connections can be shared between a global transaction and local transactions, and they can switch between them.

Each connection has one of the following modes.

Mode
Description

NO_TXN

There is no active transaction that is using the current connection.

LOCAL_TXN

There is an active transaction with auto-commit mode disabled that is using the current connection. Depending on the connection mode, it is impossible to call the prepare(), commit(), rollback(), forget(), and end() methods, and an XAException may occur.

GLOBAL_TXN

There is an active transaction that is using the current connection. Depending on the connection mode, it is impossible to call the commit(), rollback(), setAutoCommit() and setSavepoint() methods, and an SQLException may occur.

Depending on the operation status, each connection automatically switches between the following modes. When a connection is initialized, it always operates in NO_TXN mode.

Current Mode
Switching to NO_TXN
Switching to LOCAL_TXN
Switching to GLOBAL_TXN

NO_TXN

-

When auto-commit mode is disabled, and a DML statement is executed.

When the end() method is called on an XAResource that has been obtained from XAConnection.

LOCAL_TXN

When a DDL statement is executed, or the commit() or rollback() method is called.

-

Impossible

GLOBAL_TXN

When the end() method is called on an XAResource that has been obtained from XAConnection.

Impossible

-


Tibero XA Packages

Tibero follows the XA standard and supports the following classes in com.tmax.tibero.jdbc.ext, a distributed transaction package.

  • TbXAConnection

  • TbXADataSource

  • TbXAException

  • TbXAResource

  • TbXid


Components of XA Interfaces

This section describes the components of XA interfaces that are defined in the JDBC 2.0 standard package.

XADataSource Interface

The following is the interface defined in javax.sql.XADataSource.

public interface XADataSource
{
    XAConnection getXAConnection() throws SQLException;
    XAConnection getXAConnection(String user, String password) throws SQLException;
    ...
}

In tbJDBC, the interface is provided by the com.tmax.tibero.jdbc.ext.TbXADataSource class. By extending TbConnectionPoolDataSource, it is possible to use the features of the connection for a general DataSource.

XAConnection Interface

The following is the interface defined in javax.sql.XAConnection.

public interface XAConnection extends PooledConnection
{
  javax.transaction.xa.XAResource getXAResource() throws SQLException;
}

In tbJDBC, the interface is provided by the com.tmax.tibero.jdbc.ext.TbXAConnection class.

XAResource Interface

The following is the interface defined in javax.transaction.xa.XAResource.

public interface XAResource
{
    void commit(Xid xid, boolean onePhase) throws XAException; 
    void end(Xid xid, int flags) throws XAException;
    void forget(Xid xid) throws XAException; 
    int prepare(Xid xid) throws XAException; 
    int rollback(Xid xid) throws XAException;
    void start(Xid xid, int flags) throws XAException; 
    boolean isSameRM(XAResource xares) throws XAException;
}

In tbJDBC, the interface is provided by the com.tmax.tibero.jdbc.ext.TbXAResource class.

The following methods can be specified with the XAResource interface.

Method
Description

Start

Starts a certain branch of a transaction related to the XID, restarts an existing

transaction, or joins modifications.

End

Indicates that a particular branch of a transaction related to the XID has been closed (whether it was normally closed or failed), or suspends an existing

transaction.

Prepare

Prepares the modifications performed in the current transaction branch.

Commit

Commits modifications of the current transaction branch.

Rollback

Rolls back the changes of the current transaction branch.

Forget

Ignores the transaction branch specified by the resource manager.

Recover

Returns a list of transaction branches that have been prepared or completed.

isSameRM

Determines if two XA resource objects are included in the same resource manager.

Start

Starts a certain branch of a transaction related to the XID, restarts an existing transaction, or joins modifications.

  • Syntax

void start(Xid xid, int flags)

  • Parameter

Parameter
Description

xid

ID of the global transaction related to the current resource object.

flags

Specifies one of the following.

  • XAResource.TMNOFLAGS: Starts a new transaction branch.

  • XAResource.TMJOIN: Joins subsequent operations to the existing transaction branch.

  • XAResource.TMRESUME: Resumes a stopped transaction.

  • TbXAResource.TBRTMSERIALIZABLE: Starts a serializable transaction.

  • TbRTMREADONLY: Starts a read-only transaction.

  • TbXAResource.TBRTMREADWRITE: Starts a read/write transaction.

  • TbXAResource.TBRTRANSLOOSE: Starts a loosely-coupled transaction.

End

Indicates that a particular branch of a transaction related to the XID has been closed (whether it was normally closed or failed), or suspends an existing transaction.

  • Syntax

void end(Xid xid, int flags)

  • Parameter

Parameter
Description

xid

ID of the global transaction related to the current resource object.

flags

Specifies one of the following.

  • XAResource.TMSUCCESS: Indicates that the current transaction branch has succeeded.

  • XAResource.TMFAIL: Indicates that the current transaction branch has failed.

  • XAResource.TMSUSPEND: Suspends the current transaction branch.

Prepare

Prepares the modifications performed in the current transaction branch, and is the first phase of a two-phase commit process. If there is only one transaction in a distributed transaction, it is not necessary to call the prepare() method.

  • Syntax

int prepare(Xid xid)

  • Parameter

Parameter
Description

xid

ID of the global transaction related to the current resource object.

  • Return values

    This method returns one of the following values.

Return Value
Description

XAResource.XA_RDONLY

The current transaction branch can perform only SELECT statements because it runs in read-only mode.

XAResource.XA_OK

The current transaction branch can perform any kind of update operation.

Commit

Commits modifications of the current transaction branch, and is the second phase of a two-phase commit process. This is performed after all transaction branches are prepared.

  • Syntax

void commit(Xid xid, boolean isOnePhase)

  • Parameter

Parameter
Description

xid

ID of the global transaction related to the current resource object.

isOnePhase

Performs commit operations as follows:

  • If set to 'true': one-phase commit operation.

  • If set to 'false' : two-phase commit operation.

Rollback

Rolls back the changes of the current transaction branch.

  • Syntax

void rollback(Xid xid)

  • Parameter

Parameter
Description

xid

ID of the global transaction related to the current resource object.

Forget

Ignores the transaction branch specified by the resource manager.

  • Syntax

void forget(Xid xid)

  • Parameter

Parameter
Description

xid

ID of the global transaction related to the current resource object.

Recover

Returns a list of transaction branches that have been prepared or completed.

  • Syntax

Xid[] recover(int flag)

  • Parameter

파라미터
설명

flag

Specifies one of the following.

  • XAResource.TMSTARTSCAN: Returns transactions that have been prepared.

  • XAResource.TMENDSCAN: Returns transactions that have been completed.

  • XAResource.TMNOFLAGS: Returns all transactions.

isSameRM

Determines if two XA resource objects are included in the same resource manager.

  • Syntax

boolean isSameRM(XAResource aResource)

  • Parameter

Parameter
Description

aResource

Resource object to be compared with the current resource object.


XID Interface

The transaction manager creates an XID object, and uses it to manage branches of a distributed transaction. Each transaction branch is granted its own XID.

An XID contains the following information:

  • Format Identifier (4bytes) Represents a Java transaction manager and cannot be NULL. The following method is used.

public int getFormatId()

  • Global Transaction Identifier (64 bytes) Transaction branches in the same distributed transaction share the same value for this field. The following method is used.

public byte[] getGlobalTransactionId()

  • Branch Qualifier (64 bytes) The following method is used.

public byte[] getBracheQualifier()

The following is the interface defined in javax.transaction.xa.Xid.

public TbXid(int formatId, byte[] globalId, byte[] branchId) throws XAException

In tbJDBC, the interface is provided as the com.tmax.tibero.jdbc.ext.TbXid class.


Examples of Distributed Transactions

The following is the implementation order of a two-phase distributed transaction environment that contains two transaction branches.

  1. Start transaction branch #1.

  2. Start transaction branch #2.

  3. Execute a DML statement in transaction branch #1.

  4. Execute a DML statement in transaction branch #2.

  5. End the transaction of transaction branch #1.

  6. End the transaction of transaction branch #2.

  7. Prepare transaction branch #1.

  8. Prepare transaction branch #2.

  9. Commit transaction branch #1.

  10. Commit transaction branch #2.

The following example shows a Java program implemented according to that process.

import java.sql.*;
import javax.sql.XAConnection;
import javax.transaction.xa.XAResource; 
import com.tmax.tibero.jdbc.ext.*;

public class TwoBranchXA
{
  public static void main(String args[]) throws SQLException
  {
      createBaseTable(); 
      try {
            // Create XADataSource instance 
            TbXADataSource xads1 = new TbXADataSource();
            xads1.setUrl("jdbc:tibero:thin:@localhost:7629:dbsvr"); 
            xads1.setUser("tibero");
            xads1.setPassword("tmax");
                
            TbXADataSource xads2 = new TbXADataSource(); 
            xads2.setUrl("jdbc:tibero:thin:@localhost:8629:dbsvr"); 
            xads2.setUser("wrpark");
            xads2.setPassword("tmax");
                
            // Get the XA connection
            XAConnection xacon1 = xads1.getXAConnection(); 
            XAConnection xacon2 = xads2.getXAConnection();
                
            // Get the physical connection
            Connection conn1 = xacon1.getConnection(); 
            Connection conn2 = xacon2.getConnection();
                
            // Get the XA resource
            XAResource xars1 = xacon1.getXAResource(); 
            XAResource xars2 = xacon2.getXAResource();
                
            // Create the Xid
            Xid xid1 = createXid(1); 
            Xid xid2 = createXid(2);
                
            // Start the resource
            xars1.start(xid1, XAResource.TMNOFLAGS); 
            xars2.start(xid2, XAResource.TMNOFLAGS);
                
            // Execute SQL operations 
            execute1(conn1); 
            execute2(conn2);
                
            // End both the branches 
            xars1.end(xid1, XAResource.TMSUCCESS); 
            xars2.end(xid2, XAResource.TMSUCCESS);
                
            // Prepare the resource manager 
            int pre1 = xars1.prepare(xid1); 
            int pre2 = xars2.prepare(xid2);
                
            // Commit or rollback
            if (pre1 == XAResource.XA_RDONLY || pre1 == XAResource.XA_OK) 
                xars1.commit(xid1, false);
            else
                xars1.rollback(xid1);
                    
            if (pre2 == XAResource.XA_RDONLY || pre2 == XAResource.XA_OK) 
                xars2.commit(xid2, false);
            else
                xars2.rollback(xid2);
                    
            // Clear 
            conn1.close(); 
            conn1 = null; 
            conn2.close(); 
            conn2 = null;
                
            xacon1.close(); 
            xacon1 = null; 
            xacon2.close(); 
            xacon2 = null;
        }
    catch (Exception se) {
            se.printStackTrace();
        }
    }
}

Last updated