[seata]获取不到后置镜像导致会滚失败compare row failed, rowKey 105_105, reason [newRow is null]

2024-07-15 259 views
9

报错获取不到后置镜像,导致后面undo判断失败认为是脏记录导致回滚失败,我也没进行其他影响after镜像的操作啊 A服务调用B服务然后在调用C服务其中B分支回滚成功 求大神答疑 image

回答

3

请按规范的issue填写,版本什么都没有做提供,无法判断

4

先提供下当时update的语句,seata版本,是否存在修改主键值?

4

seata版本为1.5.1,id为主键

 <insert id="create">
        INSERT INTO `t_order` (`id`, `user_id`, `product_id`, `count`, `money`, `status`)
        VALUES (NULL, #{userId}, #{productId}, #{count}, #{money}, 0);
    </insert>
8

insert的前镜像是空的,不会出现前镜像有值后镜像无值的情况,建议先看下依赖是否冲突到底是不是1.5.1版本的client依赖,或者直接提供可复现的demo

6

好的,我来看下

7

老哥现在有啥眉目么

0

目前还没有时间看,这周末我看下

6

通过debug翻阅源码发现,在生成后置镜像中,如果insert语句中有主键字段,后面在生成后置镜像查询时就会有两个id,一个是主键id还有一个是你插入语句中的id,然后在回滚对比中,就会将两个id组成id_id,如105_105,实则应该是105即可,所以找不到105_105。

解决方法:将insert语句改为:INSERT INTO `t_order` (`user_id`, `product_id`, `count`, `money`, `status`) VALUES (#{userId}, #{productId}, #{count}, #{money}, 0);就可以了

问题所在:

Set<String> columns = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
//这一步会将插入的所有字段添加到查询语句中,如果插入语句包含id,那么下面一行代码就会重复添加主键
columns.addAll(recognizer.getInsertColumns());
//添加主键字段
columns.addAll(pkColumnNameList);
//此时组成后置镜像查询语句就是select id, user_id,count....,id from .... where id in(?)
for (String columnName : columns) {
    selectSQLJoin.add(columnName);
}
1

这时候个set,如果去重失败了,麻烦看下是不是字段大小写和数据库大小写不同?

8

使用分布式id作为主键进行插入,回滚时和题主报一样的错误,查看undolog表中的插入数据,回滚字段的json中确实包含了两个主键id,导致回滚时一直报找不到行记录。我想问下at模式下使用分布式id插入数据库要如何处理,保证回滚不会异常。1.5.3版本

6

加了sql'' 导致的

3

没明白,能不能详细说说

3

感谢,解决了,太妙了