关于Mybatis-Plus的insertOrUpdate()方法使用时的问题与解决—数值精度转化问题

1 问题描述

今天在使用Mybatis-Plus的insertOrUpdate()方法时,新增能成功,编辑无法成功,报错如下:

我很好奇,明明我前端执行的是编辑逻辑,并不需要phone_number字段,而insertOrUpdate()方法为什么会执行INSERT语句?

而这里的phone_number报错也很好理解,就是因为数据库我设置了该字段NOT NULL,而编辑操作误执行为插入操作,因此并没有设置phone_number字段的值,于是就报错。因此现在问题就是研究为什么insertOrUpdate()方法没有正常执行UPDATE语句。

2 问题解决

2.1 问题排查分析

2.1.1 问题排查

首先,我数据库使用雪花算法生成主键id。

在打断点调试程序后发现,前端传来的id是1974004895060627500:

再前往浏览器的localstorage查看存储在前端的用户id也是1974004895060627500:

而数据库的主键id为1974004895060627458,可以发现,后三位不一样:

之所以查看id的问题,是因为insertOrUpdate()方法根据是否有id来判断当前是新增还是编辑数据,如果有id,则说明是编辑(先根据id能查到才能修改);如果没有id,则说明是新增。

现在,问题大概就清晰了,可能是因为后端返回给前端正确的id,但是不知道为什么前端存储了错误的id,导致前端使用错误的id编辑用户,查不到正确的用户,因此insertOrUpdate()就判断此次是新增用户,从而使用insert语句,而insert语句中phone_number是必传字段,不能为空,因此抛出异常。

那么为什么id从后端传到前端会发生后三位的错误情况?

2.1.2 底层逻辑

从过查询资料和AI,得到结论:

雪花算法生成的Long类型主键ID(如1974004895060627458),在数据库用bigint存储,这类ID是19位超大整数。

而前端的JavaScript 环境,其数字类型基于 IEEE 754 双精度浮点数标准,安全整数范围(53位)是 ±2^53 - 1(即 ±9,007,199,254,740,991),约等于 16 位十进制数。

当后端的主键ID超过这个范围时,JavaScript 会自动进行舍入或截断,导致 ID 值在前端存储和回传时发生改变

因此,后三位被四舍五入为500了,导致前端存储的主键id是错误的。

2.2 解决方案

在后端接收请求的DTO类型或后端返回响应的VO类型的属性ID添加String的序列化注解:

java 复制代码
@JsonSerialize(using = ToStringSerializer.class)

该注解会将Long类型的属性序列化为JSON字符串时直接转化为String字符串,从而保证主键ID保证完整的精度,前端接收到的响应也是String类型的主键ID,从而避免了数值类型转化的精度问题。

相关推荐
rannn_111几秒前
【苍穹外卖|Day4】套餐页面开发(新增套餐、分页查询、删除套餐、修改套餐、起售停售)
java·spring boot·后端·学习
qq_12498707534 分钟前
基于JavaWeb的大学生房屋租赁系统(源码+论文+部署+安装)
java·数据库·人工智能·spring boot·计算机视觉·毕业设计·计算机毕业设计
我是伪码农9 分钟前
Vue 2.3
前端·javascript·vue.js
短剑重铸之日10 分钟前
《设计模式》第十一篇:总结
java·后端·设计模式·总结
若鱼191933 分钟前
SpringBoot4.0新特性-Observability让生产环境更易于观测
java·spring
夜郎king34 分钟前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
倒流时光三十年36 分钟前
SpringBoot 数据库同步 Elasticsearch 性能优化
数据库·spring boot·elasticsearch
觉醒大王41 分钟前
强女思维:着急,是贪欲外显的相。
java·论文阅读·笔记·深度学习·学习·自然语言处理·学习方法
努力学编程呀(๑•ี_เ•ี๑)1 小时前
【在 IntelliJ IDEA 中切换项目 JDK 版本】
java·开发语言·intellij-idea
码农小卡拉1 小时前
深入解析Spring Boot文件加载顺序与加载方式
java·数据库·spring boot