Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
xuzigang404 opened this issue Jul 10, 2022 · 16 comments

Comments

@xuzigang404
Copy link

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

@funky-eyes
Copy link
Contributor

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

@funky-eyes
Copy link
Contributor

funky-eyes commented Jul 10, 2022

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

@xuzigang404
Copy link
Author

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>

@funky-eyes
Copy link
Contributor

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>

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

@xuzigang404
Copy link
Author

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>

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

小白能力有限没找到问题所在,已将复现demo上传,大佬看一下
https://github.com/xuzigang404/cloud2022/tree/master

@funky-eyes
Copy link
Contributor

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>

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

小白能力有限没找到问题所在,已将复现demo上传,大佬看一下 https://github.com/xuzigang404/cloud2022/tree/master

好的,我来看下

@xuzigang404
Copy link
Author

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>

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

小白能力有限没找到问题所在,已将复现demo上传,大佬看一下 https://github.com/xuzigang404/cloud2022/tree/master

好的,我来看下

老哥现在有啥眉目么

@funky-eyes
Copy link
Contributor

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>

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

小白能力有限没找到问题所在,已将复现demo上传,大佬看一下 https://github.com/xuzigang404/cloud2022/tree/master

好的,我来看下

老哥现在有啥眉目么

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

@liuyu1023
Copy link

liuyu1023 commented Jul 26, 2022

通过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);
}

@funky-eyes
Copy link
Contributor

通过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);
}

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

@liong911
Copy link

liong911 commented Apr 12, 2023

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

@funky-eyes
Copy link
Contributor

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

加了sql'' 导致的

@liong911
Copy link

没明白,能不能详细说说

@funky-eyes
Copy link
Contributor

#4652

@funky-eyes
Copy link
Contributor

#4985

@liong911
Copy link

感谢,解决了,太妙了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants