【问题标题】:JTA XAResource multiple databases: what if two phase commit fails after prepareJTA XAResource 多个数据库:如果准备后两阶段提交失败怎么办
【发布时间】:2015-02-28 00:02:52
【问题描述】:

我需要做一个 POC,它在核心 Java 应用程序(不是 Web)中使用 JTA XA 资源和 MySQL,而不使用任何框架。所有文章和示例都显示使用单一数据源提交。虽然我已经使用两个数据库完成了分布式事务,但我对使用 XA 资源的“两阶段提交”有疑问/查询。我的代码是:

 public static void main(String[] args) {
    DataSource dataSourceRemote = ConnectionManager.getDatasourceRemote();
    DataSource dataSourceLocal = ConnectionManager.getDatasourceLocal();
XAResource xaRes;
    XAResource xaRes2; 
    XID xid, xid2;
    try {

        XADataSource xaDataSourceLocal;
        XAConnection xaCon;

        //XID xid;
        Connection con;
        Statement stmt;
        int ret;

        XADataSource xaDataSourceRemote;
        XAConnection xaCon2;

        //XID xid2;
        Connection con2;
        Statement stmt2;
        int ret2;xaDataSourceLocal = (XADataSource) dataSourceLocal;

        xaCon = xaDataSourceLocal.getXAConnection("root", "root");
        con = xaCon.getConnection();
        stmt = con.createStatement();
        xaRes = xaCon.getXAResource();

        xaDataSourceRemote = (XADataSource) dataSourceRemote;

        xaCon2 = xaDataSourceRemote.getXAConnection("root", "root");
        con2 = xaCon2.getConnection();
        stmt2 = con2.createStatement();
        xaRes2 = xaCon2.getXAResource();

        con.setAutoCommit(false);
        con2.setAutoCommit(false);

        xid = new XID(100, new byte[] {0x01}, new byte[] {0x02});
        xid2 = new XID(101, new byte[] {0x02}, new byte[] {0x03});

        xaRes.start(xid, XAResource.TMNOFLAGS);
        String query = "insert into emp values (12, \"Sanjay\", \"12345\",  100000)";
        System.out.println(query);
        stmt.executeUpdate(query);


        xaRes2.start(xid2, XAResource.TMNOFLAGS);
        stmt2.executeUpdate("insert into emp values (11, \"Nikhil\", \"12345\",        100000)");


        xaRes2.end(xid2, XAResource.TMSUCCESS);
        xaRes.end(xid, XAResource.TMSUCCESS);ret = xaRes.prepare(xid);
        ret2 = xaRes2.prepare(xid2);

        if(ret == XAResource.XA_OK && ret2 == XAResource.XA_OK){ 
            xaRes2.commit(xid2, false);
            xaRes.commit(xid, false);

        }
        con.close();
        con2.close();
        xaCon.close();
        xaCon2.close();

        con2.close();
     } catch (XAException e) {

        e.printStackTrace();            
    } 
    catch (SQLException e) {

        e.printStackTrace();
    }
}

}

现在我的查询是:

1)有没有必要定义两个Xid,好像我把Xid2换成Xid一样,代码运行正常

2) 我在以下行进行了调试:if(ret == XAResource.XA_OK && ret2 == XAResource.XA_OK),当准备返回 XAResource.XA_OK 并且两个 xresource 的条件都为真时。现在,如果我停止对本地机器的 MySQL 服务,xaRes2.commit(xid2, false);将成功运行并且 xaRes.commit(xid, false);会抛出 XA 异常。在这种情况下,“两阶段提交”失败,因为一个数据源处于不一致状态。 我的问题是,我做得对还是有其他方法?

3) 恢复的实际用途是什么,在这种情况下,一个事务已提交,另一个事务在准备成功返回后失败

【问题讨论】:

    标签: java mysql transactions jta xa


    【解决方案1】:

    1) 我想你弄糊涂了。 XA 事务由 XID 标识/引用。因此,如果您使用两个 xID,您将有两个 XA 事务。

    您可以在两个不同的 jam 中使用相同的 XID,并且它们都可以是同一个 XA 事务的一部分。

    2) 通常,您有一个事务管理器负责处理此问题并在出现错误时进行清理。在这种情况下,您基本上需要实现这一点,并且您需要处理所有错误情况,这并非易事。为确保恢复部分正常工作,您需要测试所有不同的错误场景。例如,Oracle 允许您在提交代码路径中的不同点使提交失败以进行测试。我不确定mysql有同样的能力。

    3) 例如,如果您的 XA 事务的一个分支失败,或者您提交但您的资源管理器之一无法提交,则需要恢复。

    一般情况下,如果您使用像 Mysql 这样的数据库,则需要该数据库实现 xa 协议,否则恢复很可能无法正常工作。当然,您需要告诉数据库这是一个 xa 事务。

    【讨论】:

    • 你好 Steave,当我从“MysqlDataSource dataSource = new MysqlXADataSource();”获取数据源时,MySQL 实现了 XA。根据第 1 点中的情况。 (2) 如果一个数据源处于瞬态并抛出 XA 异常,我怎样才能将其置于一致状态?或者在这种情况下我怎么能恢复它?还有一件事,你能帮我解决这个问题吗[链接] (stackoverflow.com/questions/27854352/…)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-02
    • 2019-02-10
    • 2012-11-06
    • 2021-05-11
    • 2012-04-23
    • 2011-04-26
    • 1970-01-01
    相关资源
    最近更新 更多