At last the cud of distributed transaction those solutions article, I mentioned the three general solution, distributed transaction but there is no specific code realization, a young partner said principle know, but still can’t write code, so this article is simple chat based on XA transaction protocol, using code to implement two phase commit.

Before the actual Demo, let’s add a little XA transaction knowledge: the DTP model and the XA specification.

DTP model and the XA specification is maintained by X/Open, now the Open group, the official web site: http://www.opengroup.org/. The Open Group is an independent organization responsible for developing technical standards for various industries. Supported by well-known companies or manufacturers, mainly as follows:

Huawei is one of eight companies in the Open Group. In terms of Distributed Transaction Processing (DTP), X/Open provides the following reference documents:

  • The DTP reference model: pubs.opengroup.org/onlinepubs/…
  • The DTP XA specification: pubs.opengroup.org/onlinepubs/…

The DTP model

In Release 3 of Distributed Transaction Processing: Reference Model, there are five basic elements that make up the DTP Model:

  • Application Program (AP) : Used to define transaction boundaries (that is, define the start and end of a transaction) and operate on resources within transaction boundaries, which can be simply understood as our Application.
  • Resource Manager (RM) : Provides access to resources, such as databases and file systems.
  • Transaction Manager (TM) : Responsible for assigning unique Transaction identifiers, monitoring the execution progress of transactions, and committing and rolling back transactions.
  • Communication Resource Manager (CRM) : Controls the Communication between distributed applications within or across a TM domain.
  • Communication Protocol (CP) : Provides the underlying Communication services between distributed application nodes provided by CRM.

For more information on DTP model elements, see openGroup’s documentation. Next, let’s talk about DTP instances. A DTP instance contains at least AP, RMs, and TM parts. As shown below:

It can be seen that AP, RMs and TM all interact with each other, and the general process is as follows:

  • AP obtains database resources from RMs, which I think can be simply understood as a database link, just like the common data connection.
  • TM transaction resource manager, responsible for assigning transaction unique identifiers, monitoring transaction execution process, and responsible for transaction commit, rollback, etc. The AP binds its own transactions to TM, and TM takes care of the rest.
  • TM tells RMs (a specific database, such as MySQL) whether to perform rollback or commit based on the collected results.

So what is XA protocol? The XA specification defines interactive interfaces. As can be seen from the figure above, there are three interactive interfaces in the whole DTP. The XA specification is mainly between TM and RMs. Here’s a picture that makes sense:

Ok, so much for the DTP model and XA specification. Specifically, you can check the documentation provided by OpenGroup. The following uses our familiar MySQL database to implement a two-phase commit of XA transaction protocol.

MySQL has supported XA distributed transactions since 5.0.3 and only InnoDB storage engine. In the figure below:

There is a module on the MySQL database website dedicated to XA transactions. For details, see:

Dev.mysql.com/doc/refman/…

I won’t say anything else, but here I will mention XA transaction state. A complete transaction flow is as follows:

  • 1. Use XA START to START an XA transaction and place it underACTIVEState.
  • 2. For an ACTIVE XA transaction, we can execute the SQL statements that constitute the transaction and then publish an XA END statement. XA END puts transactions intoIDLEState.
  • 3. For oneIDLEState XA transactions, which can execute an XA PREPARE statement or an XA COMMIT… ONE PHASE statement:
    • XA PREPARE puts the transaction intoPREPAREDState. An XA RECOVER statement at this point will include the xID value of the transaction in its output, because XA RECOVER lists all XA transactions in PREPARED.
    • XA COMMIT… ONE PHASE is used to prepare and commit transactions. Xid values will not be listed by XA RECOVER because the transaction terminates.
  • For aPREPAREDFor XA transactions in state, you can issue an XA COMMIT statement to COMMIT and terminate the transaction, or issue XA ROLLBACK to ROLLBACK and terminate the transaction.

To summarize, XA transactions, Start an XA transaction with Start and set it to Active state. Transactions in Active state can execute SQL statements and set the XA transaction to IDLE with END method. In the IDLE state, you can perform the PREPARE or COMMIT operation. The one-phase operations, which are the first PHASE of the two-phase Commit, can be committed or RollBack for XA transactions in PREPARED, which is the second PHASE of the two-phase Commit.

You may have noticed that there is an XID value above, but briefly, MySQL uses an XID as an identifier for a transaction branch. The XID is defined in the XA specification, which defines an XID as having four parts:

  • Gtrid: Global Transaction Identifier, which cannot exceed 64 bytes.
  • Bqual: Branch qualifier with a maximum of 64 bytes.
  • Data: the value of xID, which is the concatenated content of GtrID and BQUal.
  • FormatId: formatId is used to record the format of gtrID and bqual, similar to the flags field in memcached.

Ok, so much for XA transaction BB, let’s implement a two-phase commit based on the XA transaction protocol through an example.

Scenario: simulation of cash + red envelope combination payment, suppose we buy 100 yuan of things, 90 yuan with cash payment, 10 red envelope payment, cash and red envelope are in different libraries.

Suppose there are two libraries: Xa_Account and xa_red_account. Mysql > select * from user_id where id, user_id, balance_amount; mysql > select * from user_id where balance_amount;

Ok, the specific code is as follows:

public class XaDemo {
    public static void main(String[] args) throws Exception{
        
        // Whether to enable logging
        boolean logXaCommands = true;

        // Get the rm of the account library (something the AP does)
        Connection accountConn = DriverManager.getConnection("JDBC: mysql: / / 106.12.12. XXXX: 3306 / xa_account? useUnicode=true&characterEncoding=utf8"."root"."xxxxx");
        XAConnection accConn = new MysqlXAConnection((JdbcConnection) accountConn, logXaCommands);
        XAResource accountRm = accConn.getXAResource();
        // Get the RM of the red envelope library
        Connection redConn = DriverManager.getConnection("JDBC: mysql: / / 106.12.12. XXXX: 3306 / xa_red_account? useUnicode=true&characterEncoding=utf8"."root"."xxxxxx");
        XAConnection Conn2 = new MysqlXAConnection((JdbcConnection) redConn, logXaCommands);
        XAResource redRm = Conn2.getXAResource();
		// The XA transaction has started
        // Global transaction
        byte[] globalId = UUID.randomUUID().toString().getBytes();
        // Just one identifier
        int formatId = 1;
		
        // Branch transaction of account
        byte[] accBqual = UUID.randomUUID().toString().getBytes();;
        Xid xid = new MysqlXid(globalId, accBqual, formatId);

        // Hongbao branch transaction
        byte[] redBqual = UUID.randomUUID().toString().getBytes();;
        Xid xid1 = new MysqlXid(globalId, redBqual, formatId);
        try {
            // The account transaction starts when the status is ACTIVE
            accountRm.start(xid, XAResource.TMNOFLAGS);
            // Simulate business
            String sql = "update account set balance_amount=balance_amount-90 where user_id=1";
            PreparedStatement ps1 = accountConn.prepareStatement(sql);
            ps1.execute();
            accountRm.end(xid, XAResource.TMSUCCESS);
			 // The transaction status of account XA is IDLE
            // The red packet branch transaction starts
            redRm.start(xid1, XAResource.TMNOFLAGS);
            // Simulate business
            String sql1 = "update account set balance_amount=balance_amount-10 where user_id=1";
            PreparedStatement ps2 = redConn.prepareStatement(sql1);
            ps2.execute();
            redRm.end(xid1, XAResource.TMSUCCESS);


            // Stage 1: Prepare the submission
            int rm1_prepare = accountRm.prepare(xid);
            int rm2_prepare = redRm.prepare(xid1);
			
			// XA transaction status: PREPARED
            // Phase 2: TM decides whether to commit or rollback based on phase 1
            boolean onePhase = false; //TM determines that there are two transaction branches, so it cannot be optimized for one-phase commit
            if (rm1_prepare == XAResource.XA_OK && rm2_prepare == XAResource.XA_OK) {
                accountRm.commit(xid, onePhase);
                redRm.commit(xid1, onePhase);
            } else{ accountRm.rollback(xid); redRm.rollback(xid1); }}catch (Exception e) {
            // An exception occursaccountRm.rollback(xid); redRm.rollback(xid1); e.printStackTrace(); }}}Copy the code

Run the program and you can see the following:

This figure clearly shows the XA transaction two-phase commit process. For more details, refer to the XA Transactions module of the MySQL database.

I hope this article is helpful for your study or work. If you think this article is good, you can pay attention to and share it with other partners, so that more people can learn. Thank you.

Welcome to pay attention to the public number [Internet crew head brother]. Pay attention to this Internet programmer, wish you and I progress together, today’s best is tomorrow’s minimum requirements.