abel533 / Mapper

Mybatis Common Mapper - Easy to use
https://mybatis.io
MIT License
7.29k stars 1.62k forks source link

关于updateByPrimaryKeySelective(T)主键异常问题 #875

Open SMSshuai opened 1 year ago

SMSshuai commented 1 year ago

通过updateByPrimaryKeySelective(T)方法更新数据的时候主键ID会变化

数据库主键ID自增 如id =10 ,11, 12,13 ,因业务需求删除了其中一个id =11。 在执行updateByPrimaryKeySelective方法是传入的数据id是12 ,但是执行成功后,实体内的id变成了11(这个id数据不存在,实体内的其他数据都正常)。 后续测试后发现,执行该方法后如果该条数据的id大于空缺数据的id就会返回空数据id。 比如:删除了id11 更新id<11的数据都正常。 更新id>11的数据都会返回id=11. 如果删除多条数据,会返回正序第一个被删掉的id。

实体增加了如下注解 @Id @KeySql(useGeneratedKeys = true) @Column(insertable = false,updatable = false) @ApiModelProperty(value="id") private Long id;

数据对比 代码执行截图

打印出来的执行代码如下 UPDATE sys_configye SET business_name = 'AppHomeStyle',business_code = 'rule',begin_time = '2022-01-01 15:08:43.0',end_time = '2030-01-12 15:08:44.0',type = 0,content_A = 4,content_B = 1,content_C = '通知公告',content_D = 'notification' WHERE id = 12;

abel533 commented 1 year ago

使用 useGeneratedKeys 时,可能是JDBC的问题,你试试纯JDBC有没有问题。

SMSshuai commented 1 year ago

使用 useGeneratedKeys 时,可能是JDBC的问题,你试试纯JDBC有没有问题。 直接用倒是可以~数据都正常。 这个问题有啥办法替代或者解决方案吗?我这边是在做数据库迁移适配的时候遇到的问题,因为使用的范围和数量都很广,逐个重写很困难。 int abcdefg(SysConfigye sysConfigye);

<update id="abcdefg" parameterType="com.sdyx.system.domain.SysConfigye" >
    UPDATE sys_configye
    SET business_name = #{businessName},
        business_code = #{businessCode},
        begin_time = #{beginTime},
        end_time = #{endTime},
        type = #{type},
        content_A = #{contentA},
        content_B = #{contentB},
        content_C = #{contentC},
        content_D = #{contentD}
        WHERE
        id = #{id}
</update>
SMSshuai commented 1 year ago

使用 useGeneratedKeys 时,可能是JDBC的问题,你试试纯JDBC有没有问题。

刚才更新了达梦数据库驱动包和最新的tk包,数据恢复正常了。可能是兼容问题。感谢回复

tk.mybatis mapper-spring-boot-starter 4.2.2
   <dependency>
            <groupId>com.dameng</groupId>
            <artifactId>DmJdbcDriver18</artifactId>
            <version>8.1.2.141</version>
        </dependency>
blackkeai commented 1 year ago

使用 useGeneratedKeys 时,可能是JDBC的问题,你试试纯JDBC有没有问题。

刚才更新了达梦数据库驱动包和最新的tk包,数据恢复正常了。可能是兼容问题。感谢回复 tk.mybatis mapper-spring-boot-starter 4.2.2 com.dameng DmJdbcDriver18 8.1.2.141

你好,你达梦数据库用的哪个 方言?

LSL1618 commented 1 year ago

我也遇到了类似情况,在使用SQLServer数据库时updateByExampleSelective执行报错,说无法更新主键标识列,查了4.2.1、4.2.2这2个版本的源码,发现在类方法SqlHelper.updateSetColumnsIgnoreVersion()中,4.2.2及以上版本多了这一段代码片

else if (column.isId() && column.isUpdatable()) {
    sql.append(column.getColumn()).append(" = ").append(column.getColumn()).append(",");
}

导致主键标识列也加入了被更新字段,SQLServer不允许自然就报错了。 别的数据库我不清楚,但这段代码片在使用SQLServer数据库时是不合理的,应该区分开。

LSL1618 commented 1 year ago

我也遇到了类似情况,在使用SQLServer数据库时updateByExampleSelective执行报错,说无法更新主键标识列,查了4.2.1、4.2.2这2个版本的源码,发现在类方法SqlHelper.updateSetColumnsIgnoreVersion()中,4.2.2及以上版本多了这一段代码片

else if (column.isId() && column.isUpdatable()) {
    sql.append(column.getColumn()).append(" = ").append(column.getColumn()).append(",");
}

导致主键标识列也加入了被更新字段,SQLServer不允许自然就报错了。 别的数据库我不清楚,但这段代码片在使用SQLServer数据库时是不合理的,应该区分开。

SMSshuai commented 1 year ago

使用 useGeneratedKeys 时,可能是JDBC的问题,你试试纯JDBC有没有问题。

刚才更新了达梦数据库驱动包和最新的tk包,数据恢复正常了。可能是兼容问题。感谢回复 tk.mybatis mapper-spring-boot-starter 4.2.2 com.dameng DmJdbcDriver18 8.1.2.141

你好,你达梦数据库用的哪个 方言?

Mysql

LSL1618 commented 1 year ago

我也遇到了类似情况,在使用SQLServer数据库时updateByExampleSelective执行报错,说无法更新主键标识列,查了4.2.1、4.2.2这2个版本的源码,发现在类方法SqlHelper.updateSetColumnsIgnoreVersion()中,4.2.2及以上版本多了这一段代码片

else if (column.isId() && column.isUpdatable()) {
    sql.append(column.getColumn()).append(" = ").append(column.getColumn()).append(",");
}

导致主键标识列也加入了被更新字段,SQLServer不允许自然就报错了。 别的数据库我不清楚,但这段代码片在使用SQLServer数据库时是不合理的,应该区分开。

gbpyz commented 2 months ago

我也遇到了类似情况,在使用SQLServer数据库时updateByExampleSelective执行报错,说无法更新主键标识列,查了4.2.1、4.2.2这2个版本的源码,发现在类方法SqlHelper.updateSetColumnsIgnoreVersion()中,4.2.2及以上版本多了这一段代码片

else if (column.isId() && column.isUpdatable()) {
    sql.append(column.getColumn()).append(" = ").append(column.getColumn()).append(",");
}

导致主键标识列也加入了被更新字段,SQLServer不允许自然就报错了。 别的数据库我不清楚,但这段代码片在使用SQLServer数据库时是不合理的,应该区分开。

我也遇到了这个情况,现在回滚到了4.2.1,请问这个问题高版本解决了吗

LSL1618 commented 2 months ago

我也遇到了类似情况,在使用SQLServer数据库时updateByExampleSelective执行报错,说无法更新主键标识列,查了4.2.1、4.2.2这2个版本的源码,发现在类方法SqlHelper.updateSetColumnsIgnoreVersion()中,4.2.2及以上版本多了这一段代码片

else if (column.isId() && column.isUpdatable()) {
    sql.append(column.getColumn()).append(" = ").append(column.getColumn()).append(",");
}

导致主键标识列也加入了被更新字段,SQLServer不允许自然就报错了。 别的数据库我不清楚,但这段代码片在使用SQLServer数据库时是不合理的,应该区分开。

我也遇到了这个情况,现在回滚到了4.2.1,请问这个问题高版本解决了吗

高版本并没有处理这个问题,所以我只好自己解决了,在所有表实体类的自增长主键标识列的@Column注解中设置 insertable=false、updatable=false,如果有自定义通用Mapper方法要检查一下是否用到 column.isInsertable()、column.isUpdatable() ,酌情处理是否去掉它两。