YvCeung commented on issue #7453:
URL:
https://github.com/apache/incubator-seata/issues/7453#issuecomment-3068607590
在 AT 模式下,RM 回滚时会对比 `before image`、`after image` 与数据库当前值(`current
record`),其中一个关键步骤是判断 `after image` 与 `current record`
是否一致,以确认数据在此期间是否被其他事务修改(即是否存在脏写风险)。
目前的问题很可能出现在这一阶段。
在构造 `after image` 的过程中,自定义了序列化逻辑:将 `DmdbTimestamp` 转换为 `Instant` 并序列化为 UTC
时间戳。
而在反序列化阶段,为了恢复 `DmdbTimestamp`,使用如下方式进行构造:
```java
private Object createDmdbTimestamp(Instant instant) throws Exception {
Class<?> dmdbTimestampClass =
Class.forName(DM_JDBC_DRIVER_DMDB_TIMESTAMP);
Method valueOfMethod = dmdbTimestampClass.getMethod(VALUE_OF,
ZonedDateTime.class);
return valueOfMethod.invoke(null, instant.atZone(zoneId));
}
```
这段代码会在原始 UTC 时间的基础上,根据本地默认时区(如 `+08:00`)生成对应的 `ZonedDateTime`,从而得到带时区标记的
`DmdbTimestamp` 实例。
举例来说,原始序列化的是 `2025-04-19 10:08:21.617`,反序列化后实际变成了 `2025-04-19
10:08:21.617000 +08:00`。
而另一方面,`current record` 是通过 JDBC 直接从数据库查询得到的原始值,此过程**不会走自定义的反序列化逻辑**,因此拿到的是
`2025-04-19 10:08:21.617`,即**没有时区标记、也没有微秒补齐的版本**。
由于这两者在精度或元信息上存在差异(如纳秒位补零、时区标记等),`Objects.deepEquals()`
最终判断两者不相等,导致回滚失败,误判为数据发生了变更。所以问题在于比较的逻辑不严谨
基于此,我打算修改字段比较逻辑,对于 `DmdbTimestamp` 类型,优先将其统一转换为 `Instant`(UTC
时间点)进行比较,避免因时区、格式或纳秒补齐等非本质差异导致误判。
cc @funky-eyes
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]