From 56a2f1458ed1c4528c17a1f2be18689b9c8f171c Mon Sep 17 00:00:00 2001 From: shukai <525718210@qq.com> Date: Sat, 15 Feb 2025 18:01:23 +0800 Subject: [PATCH] bugfix: modify XA mode pre commit transaction from commit phase to before close phase (#7102) --- changes/en-us/2.x.md | 1 + changes/zh-cn/2.x.md | 1 + .../rm/datasource/xa/ConnectionProxyXA.java | 76 ++++++++++--------- .../datasource/xa/ConnectionProxyXATest.java | 4 +- 4 files changed, 44 insertions(+), 38 deletions(-) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index c323121938b..93faf87d4ca 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -19,6 +19,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#7124](https://github.com/apache/incubator-seata/pull/7124)] bugfix: GlobalTransactionScanner.afterPropertiesSet need do scanner check - [[#7135](https://github.com/apache/incubator-seata/pull/7135)] treating a unique index conflict during rollback as a dirty write - [[#7150](https://github.com/apache/incubator-seata/pull/7150)] The time difference between the raft node and the follower node cannot synchronize data +- [[#7102](https://github.com/apache/incubator-seata/pull/7150)] bugfix: modify XA mode pre commit transaction from commit phase to before close phase ### optimize: diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index 683c5556ccd..b4c6eac7faf 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -19,6 +19,7 @@ - [[#7124](https://github.com/apache/incubator-seata/pull/7124)] GlobalTransactionScanner.afterPropertiesSet方法需要做扫描检查 - [[#7135](https://github.com/apache/incubator-seata/pull/7135)] 回滚时遇到唯一索引冲突视为脏写 - [[#7150](https://github.com/apache/incubator-seata/pull/7150)] raft节点之前时间差,follower节点无法同步数据 +- [[#7102](https://github.com/apache/incubator-seata/pull/7150)] 将XA模式预提交事务从提交阶段修改为关闭前阶段 ### optimize: diff --git a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/xa/ConnectionProxyXA.java b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/xa/ConnectionProxyXA.java index 709263d88cc..8ceaa80696d 100644 --- a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/xa/ConnectionProxyXA.java +++ b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/xa/ConnectionProxyXA.java @@ -183,6 +183,9 @@ public void setAutoCommit(boolean autoCommit) throws SQLException { commit(); } } else { + if (this.xaBranchXid != null && currentAutoCommitStatus) { + return; + } if (xaActive) { throw new SQLException("should NEVER happen: setAutoCommit from true to false while xa branch is active"); } @@ -230,36 +233,6 @@ public void commit() throws SQLException { if (!xaActive || this.xaBranchXid == null) { throw new SQLException("should NOT commit on an inactive session", SQLSTATE_XA_NOT_END); } - try { - // XA End: Success - try { - end(XAResource.TMSUCCESS); - } catch (SQLException sqle) { - // Rollback immediately before the XA Branch Context is deleted. - String xaBranchXid = this.xaBranchXid.toString(); - rollback(); - throw new SQLException("Branch " + xaBranchXid + " was rollbacked on committing since " + sqle.getMessage(), SQLSTATE_XA_NOT_END, sqle); - } - long now = System.currentTimeMillis(); - checkTimeout(now); - setPrepareTime(now); - int prepare = xaResource.prepare(xaBranchXid); - // Based on the four databases: MySQL (8), Oracle (12c), Postgres (16), and MSSQL Server (2022), - // only Oracle has read-only optimization; the others do not provide read-only feedback. - // Therefore, the database type check can be eliminated here. - if (prepare == XAResource.XA_RDONLY) { - // Branch Report to TC: RDONLY - reportStatusToTC(BranchStatus.PhaseOne_RDONLY); - } - } catch (XAException xe) { - // Branch Report to TC: Failed - reportStatusToTC(BranchStatus.PhaseOne_Failed); - throw new SQLException( - "Failed to end(TMSUCCESS)/prepare xa branch on " + xid + "-" + xaBranchXid.getBranchId() + " since " + xe - .getMessage(), xe); - } finally { - cleanXABranchContext(); - } } } @@ -336,13 +309,44 @@ private void checkTimeout(Long now) throws XAException { @Override public void close() throws SQLException { try (ResourceLock ignored = resourceLock.obtain()) { - rollBacked = false; - if (isHeld() && shouldBeHeld()) { - // if kept by a keeper, just hold the connection. - return; + try { + if (xaActive && this.xaBranchXid != null) { + // XA End: Success + try { + end(XAResource.TMSUCCESS); + } catch (SQLException sqle) { + // Rollback immediately before the XA Branch Context is deleted. + String xaBranchXid = this.xaBranchXid.toString(); + rollback(); + throw new SQLException("Branch " + xaBranchXid + " was rollbacked on committing since " + sqle.getMessage(), SQLSTATE_XA_NOT_END, sqle); + } + long now = System.currentTimeMillis(); + checkTimeout(now); + setPrepareTime(now); + int prepare = xaResource.prepare(xaBranchXid); + // Based on the four databases: MySQL (8), Oracle (12c), Postgres (16), and MSSQL Server (2022), + // only Oracle has read-only optimization; the others do not provide read-only feedback. + // Therefore, the database type check can be eliminated here. + if (prepare == XAResource.XA_RDONLY) { + // Branch Report to TC: RDONLY + reportStatusToTC(BranchStatus.PhaseOne_RDONLY); + } + } + } catch (XAException xe) { + // Branch Report to TC: Failed + reportStatusToTC(BranchStatus.PhaseOne_Failed); + throw new SQLException( + "Failed to end(TMSUCCESS)/prepare xa branch on " + xid + "-" + xaBranchXid.getBranchId() + " since " + xe + .getMessage(), xe); + } finally { + cleanXABranchContext(); + rollBacked = false; + if (isHeld() && shouldBeHeld()) { + // if kept by a keeper, just hold the connection. + } else { + originalConnection.close(); + } } - cleanXABranchContext(); - originalConnection.close(); } } diff --git a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/xa/ConnectionProxyXATest.java b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/xa/ConnectionProxyXATest.java index 77f0f681a88..b95d9bb147c 100644 --- a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/xa/ConnectionProxyXATest.java +++ b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/xa/ConnectionProxyXATest.java @@ -84,8 +84,8 @@ public void testXABranchCommit() throws Throwable { connectionProxyXA.commit(); - Mockito.verify(xaResource).end(any(Xid.class), any(Integer.class)); - Mockito.verify(xaResource).prepare(any(Xid.class)); + Mockito.verify(xaResource, times(0)).end(any(Xid.class), any(Integer.class)); + Mockito.verify(xaResource, times(0)).prepare(any(Xid.class)); } @Test