Java Distributed Transactions (Multiple Data Sources)

In the past few days, I have been working on how to implement distributed transactions. I found a lot of information, but most of them are similar. The number of Oracle, SQL Server, and Mysql has been tested, and distributed transactions are only supported by Mysql5.0 or above.
For these, the main reason is that I have never been in contact with distributed transactions before, and I have found some information about distributed transaction databases by mistake. Haha, the result is not what I need at present.
There were a lot of errors during the test, but it failed all the time, thinking it was a problem with user permissions and database services, but when everything was well configured, it still failed. It turned out that I imported some common JDBC connection packages, so I searched wildly for jar packages that implement XA transactions.
Mysql: mysql-connector-java-5.1.6-bin.jar
SQL Server: sqljdbc.jar
Oracle: ojdbc14.jar
These packages are used to run smoothly. These jar packages will be attached later.
Well, attach the source code:

import com.microsoft.sqlserver.jdbc.SQLServerXADataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import java.sql.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sql.*;
import javax.transaction.xa.*;
import oracle.jdbc.xa.client.OracleXADataSource;

public class Mutil_DataSource_Test {
    public static void main(String[] args){
        Mutil_DataSource_Test mdt = new Mutil_DataSource_Test();
        try {
            mdt.test1();
        } catch (Exception ex) {
            System.out.println("除SQLException、XAException之外的异常: \n");
            Logger.getLogger(Mutil_DataSource_Test.class.getName()).log(Level.SEVERE, null, ex);
         }
    }

    class MyXid implements Xid{
        int formatId;
        byte globalTransactionId[];
        byte branchQualifier[];
        public MyXid(){

        }
        public MyXid(int formatId,byte[] globalTransactionId,byte[] branchQualifier){
             this.formatId = formatId;
            this.globalTransactionId = globalTransactionId;
            this.branchQualifier = branchQualifier;
        }

        public int getFormatId() {
            return this.formatId;
        }
        public void setFormatId(int formatId){
            this.formatId = formatId;
        }
        public byte[] getGlobalTransactionId() {
            return this.globalTransactionId;
        }
        public void setGlobalTransactionId(byte[] globalTransactionId){
            this.globalTransactionId = globalTransactionId;
        }
        public byte[] getBranchQualifier() {
            return this.branchQualifier;
        }
        public void setBranchQualifier(byte[] branchQualifier){
            this.branchQualifier = branchQualifier;
        }
    }

    //Multiple database test
    public void test1() {
        //Define the required variables
         Connection mysqlCn = null;
        Connection sqlCn = null;
        Connection mysqlCn2 = null;
        Connection oraCn = null;

        MysqlXADataSource mysqlDs = null;
        SQLServerXADataSource sqlDs = null;
        MysqlXADataSource mysqlDs2 = null;
        OracleXADataSource oraDs = null;

        XAConnection xamysqlCn = null;
        XAConnection xasqlCn = null;
        XAConnection xamysqlCn2 = null;
        XAConnection xaoraCn = null;

        XAResource xamysqlRes = null;
        XAResource xasqlRes = null;
        XAResource xamysqlRes2 = null;
        XAResource xaoraRes = null;

        Xid mysqlXid = null;
        Xid sqlXid = null;
        Xid mysqlXid2 = null;
        Xid oraXid = null;

        Statement mysqlpst = null;
        Statement sqlpst = null;
        Statement mysqlpst2 = null;
        Statement orapst = null;
    try{
        //获得数据源
        mysqlDs = new MysqlXADataSource();
        mysqlDs.setURL("jdbc:mysql://localhost:3306/test");
        mysqlDs2 = new MysqlXADataSource();
        mysqlDs2.setURL("jdbc:mysql://10.10.10.119:3306/test");
        sqlDs = new SQLServerXADataSource();
        sqlDs.setURL("jdbc:sqlserver://10.10.10.119:1433;DatabaseName=RTC;loginTimeout=20;user=sa;password=chgpwd122105");
//        sqlDs.setUser("sa");
//        sqlDs.setPassword("chgpwd122105");
//        sqlDs.setServerName("10.10.10.119");
//        sqlDs.setPortNumber(1433);
//        sqlDs.setDatabaseName("RTC");
        oraDs = new OracleXADataSource();
        oraDs.setURL("jdbc:oracle:thin:@10.10.10.119:1521:WMS");
        //获得连接
        xamysqlCn = mysqlDs.getXAConnection("root", "9999");
System.out.println("xamysqlCn: "+xamysqlCn);
        xasqlCn = sqlDs.getXAConnection();
System.out.println("xasqlCn: "+xasqlCn);
        xamysqlCn2 = mysqlDs2.getXAConnection("root", "9999");
System.out.println("xamysqlCn2: "+xamysqlCn2);
        xaoraCn = oraDs.getXAConnection("tiger", "tiger");
System.out.println("xaoraCn: "+xaoraCn);

        mysqlCn = xamysqlCn.getConnection();
        sqlCn = xasqlCn.getConnection();
        mysqlCn2 = xamysqlCn2.getConnection();
        oraCn = xaoraCn.getConnection();

        mysqlpst = mysqlCn.createStatement();
        sqlpst = sqlCn.createStatement();
        mysqlpst2 = mysqlCn2.createStatement();
        orapst = oraCn.createStatement();
        //定义XAResource
        xamysqlRes = xamysqlCn.getXAResource();
        xasqlRes = xasqlCn.getXAResource();
        xamysqlRes2 = xamysqlCn2.getXAResource();
        xaoraRes = xaoraCn.getXAResource();
        //定义Xid
        mysqlXid = new MyXid(0, new byte[]{0x01}, new byte[]{0x02});
        sqlXid = new MyXid(0, new byte[]{0x01}, new byte[]{0x03});
        mysqlXid2 = new MyXid(0, new byte[]{0x01}, new byte[]{0x04});
        oraXid = new MyXid(0, new byte[]{0x01}, new byte[]{0x05});
        //执行Mysql
        xamysqlRes.start(mysqlXid, XAResource.TMNOFLAGS);       
        mysqlpst.executeUpdate("insert into test values(4,'XA','F','Class4')");
        xamysqlRes.end(mysqlXid, XAResource.TMSUCCESS);
        //执行SQLServer
        xasqlRes.start(sqlXid, XAResource.TMNOFLAGS);
        sqlpst.executeUpdate("insert into test values('444')");
        xasqlRes.end(sqlXid, XAResource.TMSUCCESS);
        //执行Mysql
        xamysqlRes2.start(mysqlXid2, XAResource.TMNOFLAGS);
        mysqlpst2.executeUpdate("insert into test values(4,'XA','F','Class4')");
        xamysqlRes2.end(mysqlXid2, XAResource.TMSUCCESS);
        //Execute Oracle
        System.out.println("xaoraRes: "+xaoraRes);
        xaoraRes.start(oraXid, XAResource.TMNOFLAGS);
        orapst.executeUpdate("insert into test123 values( '4','44','444')");
        System.out.println("oraXid: "+oraXid);
        xaoraRes.end(oraXid, XAResource.TMSUCCESS);
        //Prepare
        int mysqlRea = xamysqlRes.prepare( mysqlXid);
        int sqlRea = xasqlRes.prepare(sqlXid);
        int mysqlRea2 = xamysqlRes2.prepare(mysqlXid2);
        int oraRea = xaoraRes.prepare(oraXid);
        //Determine whether it is ready or not, commit or rollback
        if(mysqlRea == xamysqlRes.XA_OK && mysqlRea2 == xamysqlRes.XA_OK && oraRea == xaoraRes.XA_OK && sqlRea == xasqlRes.XA_OK){
//        if(mysqlRea == xamysqlRes.XA_OK && mysqlRea2 == xamysqlRes.XA_OK && oraRea == xaoraRes.XA_OK){
//        if(mysqlRea == xamysqlRes.XA_OK && sqlRea == xasqlRes.XA_OK && mysqlRea2 == xamysqlRes.XA_OK){
//        if(mysqlRea == xamysqlRes.XA_OK && mysqlRea2 == xamysqlRes.XA_OK){
            xamysqlRes.commit(mysqlXid, false);
System.out.println("Mysql 事务提交成功!");
            xasqlRes.commit(sqlXid, false);
System.out.println("SQLServer 事务提交成功!");
            xamysqlRes2.commit(mysqlXid2, false);
System.out.println("Mysql2 transaction submitted successfully!");
            xaoraRes.commit(oraXid, false);
System.out.println("Oracle 事务提交成功!");
        }else{
            xamysqlRes.rollback(mysqlXid);
            xasqlRes.rollback(sqlXid);
            xamysqlRes2.rollback(mysqlXid2);
            xaoraRes.rollback(oraXid);
System.out.println("事务回滚成功!");
        }
    }catch(SQLException ex){
        Logger.getLogger(Mutil_DataSource_Test.class.getName()).log(Level.SEVERE, null, ex);
         try{
            xamysqlRes.rollback(mysqlXid);
            xasqlRes.rollback(sqlXid);
            xamysqlRes2.rollback(mysqlXid2);
            xaoraRes.rollback(oraXid);
        }catch(XAException e){
            System.out.println("回滚也出错咯!~");
            e.printStackTrace();
        }
    }catch(XAException ex){
        Logger.getLogger(Mutil_DataSource_Test.class.getName()).log(Level.SEVERE, null, ex);
     }finally{
        try {
        //关闭
        mysqlpst.close();
        mysqlCn.close();
        xamysqlCn.close();
        sqlpst.close();
        sqlCn.close();
        xasqlCn.close();
        mysqlpst2.close();
        mysqlCn2.close();
        xamysqlCn2.close();
        orapst.close();
        oraCn.close();
        xaoraCn.close();
        } catch (SQLException ex) {
            Logger.getLogger(Mutil_DataSource_Test.class.getName()).log(Level.SEVERE, null, ex);
         }
    }
    }
}

The distributed transaction is divided into two stages, The first stage is equivalent to a pre-commit, and the second stage is the real commit.
The first thing to implement is the Xid interface. The formatId can be understood as the ID of a global transaction. However, I did not do some exception handling in the above code, and the correct link was closed. It was just a small test by myself. These are dealt with in the project. If there is an error or failure in the first stage, it will not be submitted, and some rollback processing needs to be done. If it goes well, prepare to submit and enter the second stage. There may be problems in the second stage. If the first branch transaction is submitted successfully, and then a branch transaction fails, the data will be inaccurate. It is not known yet. Is there a way to solve some problems, it seems that XAResource.recover() can handle it, but how to solve it, I can still think of a way to solve it in the project.
I am a beginner to XA distributed transaction, and no one gave me any advice, I just found some information on the Internet. My understanding above may also be lacking or wrong. Hope that the experts can give pointers after seeing it.

Original text: http://blog.csdn.net/kangojian/article/details/6780305

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=327033352&siteId=291194637