use of com.mysql.cj.jdbc.MysqlXid in project aws-mysql-jdbc by awslabs.
the class DataSourceRegressionTest method testBug72890.
/**
* Tests fix for BUG#72890 - Java jdbc driver returns incorrect return code when it's part of XA transaction
*
* @throws Exception
*/
@Test
public void testBug72890() throws Exception {
MysqlXADataSource myDs = new MysqlXADataSource();
myDs.setUrl(BaseTestCase.dbUrl);
myDs.<SslMode>getEnumProperty(PropertyKey.sslMode).setValue(SslMode.DISABLED);
myDs.getBooleanProperty(PropertyKey.allowPublicKeyRetrieval).setValue(true);
try {
final Xid xid = new MysqlXid("72890".getBytes(), "72890".getBytes(), 1);
final XAConnection xaConn = myDs.getXAConnection();
final XAResource xaRes = xaConn.getXAResource();
final Connection dbConn = xaConn.getConnection();
final long connId = ((MysqlConnection) ((MysqlConnection) dbConn).getConnectionMutex()).getSession().getThreadId();
xaRes.start(xid, XAResource.TMNOFLAGS);
xaRes.end(xid, XAResource.TMSUCCESS);
assertEquals(XAResource.XA_OK, xaRes.prepare(xid));
// Simulate a connection hang and make sure the connection really dies.
this.stmt.execute("KILL CONNECTION " + connId);
int connAliveChecks = 4;
while (connAliveChecks > 0) {
this.rs = this.stmt.executeQuery("SHOW PROCESSLIST");
boolean connIsAlive = false;
while (!connIsAlive && this.rs.next()) {
connIsAlive = this.rs.getInt(1) == connId;
}
this.rs.close();
if (connIsAlive) {
connAliveChecks--;
System.out.println("Connection id " + connId + " is still alive. Checking " + connAliveChecks + " more times.");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
} else {
connAliveChecks = -1;
}
}
assertFalse(connAliveChecks == 0, "Failed to kill the Connection id " + connId + " in a timely manner.");
XAException xaEx = assertThrows(XAException.class, "Undetermined error occurred in the underlying Connection - check your data for consistency", new Callable<Void>() {
public Void call() throws Exception {
xaRes.commit(xid, false);
return null;
}
});
assertEquals(XAException.XAER_RMFAIL, xaEx.errorCode, "XAException error code");
dbConn.close();
xaConn.close();
} finally {
/*
* After MySQL 5.7.7 a prepared XA transaction is no longer rolled back at disconnect. It needs to be rolled back manually to prevent test failures
* in subsequent runs.
* Other MySQL versions won't have any transactions to recover.
*/
final XAConnection xaConnRecovery = myDs.getXAConnection();
final XAResource xaResRecovery = xaConnRecovery.getXAResource();
final Xid[] xidsToRecover = xaResRecovery.recover(XAResource.TMSTARTRSCAN);
for (Xid xidToRecover : xidsToRecover) {
xaResRecovery.rollback(xidToRecover);
}
xaConnRecovery.close();
}
}
use of com.mysql.cj.jdbc.MysqlXid in project aws-mysql-jdbc by awslabs.
the class XATest method createXid.
private Xid createXid(Xid xidToBranch) throws IOException {
ByteArrayOutputStream bqualOut = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream(bqualOut);
new UID().write(dataOut);
final byte[] bqual = bqualOut.toByteArray();
Xid xid = new MysqlXid(xidToBranch.getGlobalTransactionId(), bqual, 3306);
return xid;
}
use of com.mysql.cj.jdbc.MysqlXid in project note by kebukeYi.
the class XATransaction method main.
public static void main(String[] args) {
try {
// ========================== START ==========================================//
// 是否开启日志
boolean isLogging = true;
// 获取rm
Connection conn1 = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bank1?serverTimezone=UTC", "root", "123456");
XAResource accountResource = new MysqlXAConnection((com.mysql.cj.jdbc.JdbcConnection) conn1, isLogging).getXAResource();
Connection conn2 = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bank2?serverTimezone=UTC", "root", "123456");
XAResource redBagResource = new MysqlXAConnection((com.mysql.cj.jdbc.JdbcConnection) conn2, isLogging).getXAResource();
// 开始XA事物
// 全局事物
byte[] globalId = UUID.randomUUID().toString().getBytes();
// 标识
int formatId = 1;
// 分支事物一
Xid xid1 = new MysqlXid(globalId, UUID.randomUUID().toString().getBytes(), formatId);
// 分支事物二
Xid xid2 = new MysqlXid(globalId, UUID.randomUUID().toString().getBytes(), formatId);
try {
// 分支事物1开始,此时状态:ACTIVE
accountResource.start(xid1, XAResource.TMNOFLAGS);
// 模拟业务
conn1.prepareStatement("update account_info set account_balance=account_balance-10 where account_no=1").execute();
accountResource.end(xid1, XAResource.TMSUCCESS);
// 分支事物1 此时状态 IDLE
// 分支事物2开始
redBagResource.start(xid2, XAResource.TMNOFLAGS);
// 模拟业务
conn2.prepareStatement("update account_info set account_balance=account_balance+10 where account_no=2").execute();
// 存在异常
int i = 10 / 0;
redBagResource.end(xid2, XAResource.TMSUCCESS);
// 分支事物2 此时状态 IDLE
// 第一阶段:准备提交
int rm1_pre = accountResource.prepare(xid1);
int rm2_pre = redBagResource.prepare(xid2);
// XA事物 此时状态 PREPARED
// 第二阶段: TM根据根据第一阶段的情况决定提交还是回滚
// TM判断有两个事物分支,所以不能优化为一阶段提交
boolean flag = false;
if (rm1_pre == XAResource.XA_OK && rm2_pre == XAResource.XA_OK) {
accountResource.commit(xid1, flag);
redBagResource.commit(xid2, flag);
} else {
accountResource.rollback(xid1);
redBagResource.rollback(xid2);
}
// ================= END =========================//
} catch (Exception e) {
// 出现异常,也要回滚
try {
accountResource.rollback(xid1);
redBagResource.rollback(xid2);
e.printStackTrace();
} catch (XAException xaException) {
xaException.printStackTrace();
}
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
Aggregations