XA distributed transaction principle (rpm)

 

 

XA specification is distributed transaction proposed by the X / Open organization. XA specification defines the interface between the main (global) Transaction Manager (TM), and (local) resource manager (RM). Mainstream relational database products are realized XA interface.
 XA interface is bidirectional system interface, to form a communication bridge between the transaction manager (TM) and one or more resource managers (RM).
The need to introduce  XA transaction manager is because, in a distributed system, in theory, theoretically the two machines can not reach a consistent state, need to introduce a single point of coordination.
 by a global transaction manager to coordinate the management of affairs and can span multiple resources (such as databases or JMS queue) and processes. Global XA transaction manager generally use two-phase commit protocol to interact with the database.

       Explorer (resource manager): used to manage system resources, it is the way leading to the transactional resources. The database is a resource manager. Resource management should also have the ability to manage the transaction is committed or rolled back.
Transaction Manager (transaction manager): Transaction Manager is the core of distributed transaction manager. Transaction Manager to communicate with each resource manager (resource manager), coordinate and complete the transaction of business. Each branch of the transaction is identified by a unique name
Xid Xid interfaces, Xid interface is a X / Open transaction identifier XID structure Java mapping. This interface specifies three accessor method to retrieve the format global transaction ID, Global Transaction ID, and Branch Qualifier. Xid interfaces for transaction managers and resource managers to use. This interface is not visible to the application.
XA can not be submitted automatically.

Segmented submit
XA need to submit two phases: prepare and commit. 
The first stage is to prepare (prepare) phase. That is, all the participants ready to execute a transaction and lock resources needed. When participants ready, transaction manager to report is ready. 
The second stage is the stage of submission (commit). When the transaction manager to confirm that all the participants are ready, send to all participants commit command. 

Suppose there are two Connection, con1, con2, generally is as follows.

con1 = XAResouce1.getConnection...     
con2 = XAResouce2.getConnection...   
 
con1 do some thing.     
con2 do some thing.     
after they finish.     
 
pre1 = XAResouce1.prepare();     
pre2 = XAResouce2.prepare();     
 
if( both pre1 and pre2 are OK){     
XAResouce1 and 2 commit     
}else {     
XAResouce1 and 2 rollback     
}    

Transaction coordinator / manager
because XA transaction is based on the two-phase commit protocol, it requires a transaction coordinator (transaction manager) to ensure that all transaction participants have completed the preparatory work (the first phase). If the transaction coordinator (transaction manager) received news that all participants are ready, we will notify any transaction can be submitted (Phase II). MySQL play in the XA transaction is the role of the participants, not the transaction coordinator (transaction manager).


Test Case

import com.alibaba.druid.pool.xa.DruidXADataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlXid;
 
import javax.sql.XAConnection;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
 
 
class DistributeTransaction {
 
    private Properties props;
    private String propertyfile = "jdbc.properties";
 
    private String sql_1 = "delete from test3 where pk_t=3;";
    private String sql_2 = "INSERT INTO test(name) VALUES('tyz');";
 
    DistributeTransaction() {
        Connection connection_1 = null;
        Connection connection_2 = null;
        XaDataSource_1 DruidXADataSource = considered null ;
        XaDataSource_2 DruidXADataSource = considered null ;
        Xid xid_1 = null;
        Xid xid_2 = null;
        XAConnection xaConnection_1 = null;
        XAConnection xaConnection_2 = null;
        XAResource xaResource_1 = null;
        XAResource xaResource_2 = null;
 
        try {
            props = new Properties();
            props.load(getClass().getResourceAsStream(propertyfile));
        } catch (IOException io) {
            System.err.println("Error while accessing the properties file (" + propertyfile + "). Abort.");
            System.exit(1);
        }
 
        DruidXADataSource[] xaDataSources = initXADataSource();
        xaDataSource_1 = xaDataSources[0];
        xaDataSource_2 = xaDataSources[1];
 
        XAConnection[] xaConnections = initXAConnection(xaDataSource_1, xaDataSource_2);
        xaConnection_1 = xaConnections[0];
        xaConnection_2 = xaConnections[1];
 
        xaResource_1 = initXAResource(xaConnection_1);
        xaResource_2 = initXAResource(xaConnection_2);
 
        connection_1 = getDatabaseConnection(xaConnection_1);
        connection_2 = getDatabaseConnection(xaConnection_2);
 
        // create a separate branch for a common transaction
        Xid[] xids = createXID();
        xid_1 = xids[0];
        xid_2 = xids[1];
 
        try {
            execBranch(connection_1, xaResource_1, xid_1, sql_1);
            execBranch(connection_2, xaResource_2, xid_2, sql_2);
 
            if (prepareCommit(xaResource_1, xid_1) == XAResource.XA_OK &&
                    prepareCommit(xaResource_2, xid_2) == XAResource.XA_OK) {
                commitBranch(xaResource_1, xid_1);
                commitBranch(xaResource_2, xid_2);
            } else {
                throw new RuntimeException();
            }
        } catch (Exception e) {
            rollbackBranch(xaResource_1, xid_1);
            rollbackBranch(xaResource_2, xid_2);
        }
    }
 
    DruidXADataSource[] initXADataSource() {
        System.out.print("Create a XADataSource_1 data source: ");
        DruidXADataSource xaDataSource_1 = new DruidXADataSource();
        xaDataSource_1.setDbType(props.getProperty("db1.dbtype"));
        xaDataSource_1.setUrl(props.getProperty("db1.url"));
        xaDataSource_1.setUsername(props.getProperty("db1.username"));
        xaDataSource_1.setPassword(props.getProperty("db1.password"));
        System.out.println("Okay.");
 
        System.out.print("Create a XADataSource_2 data source: ");
        DruidXADataSource xaDataSource_2 = new DruidXADataSource();
        xaDataSource_2.setDbType(props.getProperty("db2.dbtype"));
        xaDataSource_2.setUrl(props.getProperty("db2.url"));
        xaDataSource_2.setUsername(props.getProperty("db2.username"));
        xaDataSource_2.setPassword(props.getProperty("db2.password"));
        System.out.println("Okay.");
        return new DruidXADataSource[]{xaDataSource_1, xaDataSource_2};
    }
 
    XAConnection[] initXAConnection(DruidXADataSource xaDataSource_1, DruidXADataSource xaDataSource_2) {
        XAConnection xaconn_1 = null;
        XAConnection xaconn_2 = null;
        try {
            System.out.print("Set up DB_1 XA connection: ");
            xaconn_1 = xaDataSource_1.getXAConnection();
            System.out.println("Okay.");
 
            System.out.print("Set up DB_2 XA connection: ");
            xaconn_2 = xaDataSource_2.getXAConnection();
            System.out.println("Okay.");
        } catch (SQLException e) {
            sqlerr(e);
        }
        return new XAConnection[]{xaconn_1, xaconn_2};
    }
 
    XAResource initXAResource(XAConnection xacon) {
        XAResource xares = null;
        try {
            System.out.print("Setting up a XA resource: ");
            xares = xacon.getXAResource ()?
            System.out.println("Okay.");
        } catch (SQLException e) {
            sqlerr(e);
        }
        return xares;
    }
 
    Connection getDatabaseConnection(XAConnection xacon) {
        Connection con = null;
        try {
            System.out.print("Establish database connection: ");
            con = xacon.getConnection();
            con.setAutoCommit(false);
            System.out.println("Okay.");
        } catch (SQLException e) {
            sqlerr(e);
        }
        return con;
    }
 
    Xid[] createXID() {
        Xid xid_1 = null;
        byte[] gid_1 = new byte[1];
        byte[] bid_1 = new byte[1];
        gid_1[0] = (Byte.decode(props.getProperty("xid.global"))).byteValue();
        bid_1[0] = (Byte.decode(props.getProperty("xid.branch.db_1"))).byteValue();
        System.out.print("Creating an XID (" + Byte.toString(gid_1[0]) + ", " + Byte.toString(bid_1[0]) + ") for DB_1: ");
        xid_1 = new MysqlXid(gid_1, bid_1, 0);
        System.out.println("Okay.");
 
        Xid xid_2 = null;
        byte[] gid_2 = new byte[1];
        byte[] bid_2 = new byte[1];
        gid_2[0] = (Byte.decode(props.getProperty("xid.global"))).byteValue();
        bid_2[0] = (Byte.decode(props.getProperty("xid.branch.db_2"))).byteValue();
        System.out.print("Creating an XID (" + Byte.toString(gid_2[0]) + ", " + Byte.toString(bid_2[0]) + ") for DB_2: ");
        xid_2 = new MysqlXid(gid_2, bid_2, 0);
        System.out.println("Okay.");
        return new Xid[]{xid_1, xid_2};
    }
 
    void execBranch(Connection con, XAResource xares, Xid xid, String sql) {
        try {
            xares.start(xid, XAResource.TMNOFLAGS);
            Statement stmt = con.createStatement();
            stmt.executeUpdate(sql);
            xares.end(xid, XAResource.TMSUCCESS);
        } catch (XAException e) {
            System.err.println("XA exception caught:");
            System.err.println("Cause  : " + e.getCause());
            System.err.println("Message: " + e.getMessage());
            e.printStackTrace ();
            throw new RuntimeException(e);
        } catch (SQLException e) {
            sqlerr(e);
            throw new RuntimeException(e);
        }
    }
 
    int prepareCommit(XAResource xares, Xid xid) {
        int rc = 0;
        System.out.print("Prepare XA branch (" +
                Byte.toString((xid.getGlobalTransactionId())[0]) + ", " +
                Byte.toString((xid.getBranchQualifier())[0]) + "): ");
        try {
            xares.prepare(xid);
        } catch (XAException e) {
            xaerr (e);
            throw new RuntimeException(e);
        }
        System.out.println("Okay.");
        return rc;
    }
 
    void commitBranch(XAResource xares, Xid xid) {
        System.out.print("Commit XA branch (" +
                Byte.toString((xid.getGlobalTransactionId())[0]) + ", " +
                Byte.toString((xid.getBranchQualifier())[0]) + "): ");
        try {
            // second parameter is 'false' since we have a two phase commit
            xares.commit(xid, false);
        } catch (XAException e) {
            xaerr (e);
            throw new RuntimeException(e);
        }
        System.out.println("Okay.");
    }
 
    void rollbackBranch(XAResource xares, Xid xid) {
        System.out.print("Rollback XA branch (" +
                Byte.toString((xid.getGlobalTransactionId())[0]) + ", " +
                Byte.toString((xid.getBranchQualifier())[0]) + "): ");
        try {
            xares.rollback(xid);
        } catch (XAException e) {
            xaerr (e);
            throw new RuntimeException(e);
        }
        System.out.println("Okay.");
    }
 
    void sqlerr(SQLException exception) {
        System.err.println("FAILED.");
        while (exception != null) {
            System.err.println("==> SQL Exception caught");
            System.err.println("--> SQLCODE : " + exception.getErrorCode());
            System.err.println("--> SQLSTATE: " + exception.getSQLState());
            System.err.println("--> Message : " + exception.getMessage());
            exception = exception.getNextException();
        }
    }
 
    void xaerr(XAException exception) {
        System.err.println("FAILED.");
        System.err.println("==> XA Exception caught");
        System.err.println("--> Cause  : " + exception.getCause());
        System.err.println("--> Message: " + exception.getMessage());
        exception.printStackTrace();
    }
 
    public static void main (String args[]) {
        new DistributeTransaction();
    }
 
}

XA performance limitations

Inefficient preparation phase lasting cost, the cost of the global state of affairs lasting, performance and local affairs difference of about 10 times;
before submission, failure is difficult to recover and isolate the problem.

----------------
Disclaimer: This article is the original article CSDN bloggers "1Vincent", and follow CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement. .
Original link: https: //blog.csdn.net/wuzhiwei549/article/details/79925618

 

Guess you like

Origin www.cnblogs.com/muxi0407/p/12112204.html