This is an automated email from the ASF dual-hosted git repository.
jimin pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git
The following commit(s) were added to refs/heads/2.x by this push:
new 9f39706fb8 bugfix: unify DmdbTimestamp comparison via UTC Instant
(#7538)
9f39706fb8 is described below
commit 9f39706fb81a4dc48092ebf79c5e153aedecf3b3
Author: xiaoyu <[email protected]>
AuthorDate: Wed Jul 23 10:29:38 2025 +0800
bugfix: unify DmdbTimestamp comparison via UTC Instant (#7538)
---
changes/en-us/2.x.md | 7 +++--
changes/zh-cn/2.x.md | 7 +++--
.../seata/rm/datasource/DataCompareUtils.java | 34 +++++++++++++++++++++
.../undo/parser/JacksonUndoLogParserTest.java | 35 ++++++++++++++++++----
4 files changed, 71 insertions(+), 12 deletions(-)
diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index 175b5979b6..825833aa5f 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -25,6 +25,7 @@ Add changes here for all PR submitted to the 2.x branch.
### bugfix:
+- [[#7538](https://github.com/apache/incubator-seata/pull/7538)] unify
DmdbTimestamp comparison via UTC Instant to prevent rollback failure
- [[#7546](https://github.com/seata/seata/pull/7546)] fix client spring
version compatible
### optimize:
@@ -52,13 +53,13 @@ Add changes here for all PR submitted to the 2.x branch.
- [[#7531](https://github.com/seata/seata/pull/7531)] Optimize the Readme and
change documents
-非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。
+Thanks to these contributors for their code commits. Please report an
unintended omission.
-<!-- 请确保您的 GitHub ID 在以下列表中 -->
+<!-- Please make sure your Github ID is in the list below -->
- [slievrly](https://github.com/slievrly)
- [YvCeung](https://github.com/YvCeung)
- [xjlgod](https://github.com/xjlgod)
-同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。
+Also, we receive many valuable issues, questions and advices from our
community. Thanks for you all.
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index f9aaef42bc..a167c7e1d0 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -25,6 +25,7 @@
### bugfix:
+- [[#7538](https://github.com/apache/incubator-seata/pull/7538)]
统一DmdbTimestamp比较方式,通过UTC比较,以防止回滚失败
- [[#7546](https://github.com/seata/seata/pull/7546)] 修复客户端spring版本兼容
@@ -51,13 +52,13 @@
- [[#7531](https://github.com/seata/seata/pull/7531)] 优化 Readme 和 change 文档
-Thanks to these contributors for their code commits. Please report an
unintended omission.
+非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。
-<!-- Please make sure your Github ID is in the list below -->
+<!-- 请确保您的 GitHub ID 在以下列表中 -->
- [slievrly](https://github.com/slievrly)
- [YvCeung](https://github.com/YvCeung)
- [xjlgod](https://github.com/xjlgod)
-Also, we receive many valuable issues, questions and advices from our
community. Thanks for you all.
+同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。
diff --git
a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java
b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java
index f20a0870a6..bd553a7be3 100644
---
a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java
+++
b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java
@@ -24,13 +24,16 @@ import org.apache.seata.rm.datasource.sql.struct.Row;
import org.apache.seata.rm.datasource.sql.struct.TableRecords;
import org.apache.seata.rm.datasource.undo.AbstractUndoLogManager;
import org.apache.seata.rm.datasource.undo.parser.FastjsonUndoLogParser;
+import org.apache.seata.rm.datasource.undo.parser.JacksonUndoLogParser;
import org.apache.seata.sqlparser.struct.TableMeta;
+import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
+import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.HashMap;
@@ -73,6 +76,23 @@ public class DataCompareUtils {
if (StringUtils.equals(currentSerializer,
FastjsonUndoLogParser.NAME)) {
convertType(f0, f1);
}
+ if (StringUtils.equals(currentSerializer,
JacksonUndoLogParser.NAME)) {
+ Object v0 = f0.getValue();
+ Object v1 = f1.getValue();
+ if (isDmdbTimestamp(v0) &&
isDmdbTimestamp(v1)) {
+ Instant i0 = toInstant(v0);
+ Instant i1 = toInstant(v1);
+ boolean equals = Objects.equals(i0, i1);
+ return equals
+ ? Result.ok()
+ : Result.buildWithParams(
+ false,
+ "Field not equals
(DmdbTimestamp), name {}, old value {}, new value {}",
+ f0.getName(),
+ v0,
+ v1);
+ }
+ }
boolean result = Objects.deepEquals(f0.getValue(),
f1.getValue());
if (result) {
return Result.ok();
@@ -249,4 +269,18 @@ public class DataCompareUtils {
}
return rowMap;
}
+
+ private static boolean isDmdbTimestamp(Object obj) {
+ return obj != null
+ &&
"dm.jdbc.driver.DmdbTimestamp".equals(obj.getClass().getName());
+ }
+
+ private static Instant toInstant(Object dmdbTimestamp) {
+ try {
+ Method toInstantMethod =
dmdbTimestamp.getClass().getMethod("toInstant");
+ return (Instant) toInstantMethod.invoke(dmdbTimestamp);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to convert DmdbTimestamp to
Instant", e);
+ }
+ }
}
diff --git
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/undo/parser/JacksonUndoLogParserTest.java
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/undo/parser/JacksonUndoLogParserTest.java
index c74e71d9c3..37e804fc72 100644
---
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/undo/parser/JacksonUndoLogParserTest.java
+++
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/undo/parser/JacksonUndoLogParserTest.java
@@ -20,10 +20,12 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.seata.common.loader.EnhancedServiceLoader;
import org.apache.seata.rm.datasource.DataCompareUtils;
import org.apache.seata.rm.datasource.sql.struct.Field;
+import org.apache.seata.rm.datasource.undo.AbstractUndoLogManager;
import org.apache.seata.rm.datasource.undo.BaseUndoLogParserTest;
import org.apache.seata.rm.datasource.undo.UndoLogParser;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
import javax.sql.rowset.serial.SerialBlob;
import javax.sql.rowset.serial.SerialClob;
@@ -40,6 +42,8 @@ import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
+import static org.mockito.Mockito.mockStatic;
+
public class JacksonUndoLogParserTest extends BaseUndoLogParserTest {
JacksonUndoLogParser parser =
@@ -149,12 +153,31 @@ public class JacksonUndoLogParserTest extends
BaseUndoLogParserTest {
Assertions.assertTrue(DataCompareUtils.isFieldEquals(field,
sameField).getResult());
}
- private boolean checkClassExists(String className) {
- try {
- Class.forName(className);
- return true;
- } catch (ClassNotFoundException e) {
- return false;
+ @Test
+ public void testSerializeAndDeserializeDmdbTimestampWithNoZone()
+ throws NoSuchFieldException, IllegalAccessException,
ClassNotFoundException, NoSuchMethodException,
+ InvocationTargetException, IOException {
+
+ try (MockedStatic<AbstractUndoLogManager> mockedStatic =
mockStatic(AbstractUndoLogManager.class)) {
+
mockedStatic.when(AbstractUndoLogManager::getCurrentSerializer).thenReturn(JacksonUndoLogParser.NAME);
+
+ java.lang.reflect.Field reflectField =
parser.getClass().getDeclaredField("mapper");
+ reflectField.setAccessible(true);
+ ObjectMapper mapper = (ObjectMapper) reflectField.get(parser);
+
+ Class<?> dmdbTimestampClass =
Class.forName("dm.jdbc.driver.DmdbTimestamp");
+ Method valueOfDateMethod = dmdbTimestampClass.getMethod("valueOf",
Date.class);
+
+ Object originalTimestamp = valueOfDateMethod.invoke(null, new
Date(1721985847000L));
+ Object originalTimestamp2 = valueOfDateMethod.invoke(null, new
Date(1721985847001L));
+ Field field = new Field("dmdb_timestamp_type",
JDBCType.TIMESTAMP.getVendorTypeNumber(), originalTimestamp);
+ Field field2 =
+ new Field("dmdb_timestamp_type",
JDBCType.TIMESTAMP.getVendorTypeNumber(), originalTimestamp2);
+ byte[] bytes = mapper.writeValueAsBytes(field);
+ Field sameField = mapper.readValue(bytes, Field.class);
+ Assertions.assertTrue(
+ DataCompareUtils.isFieldEquals(field,
sameField).getResult());
+ Assertions.assertFalse(DataCompareUtils.isFieldEquals(field,
field2).getResult());
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]