MySQL 设置double列累加,导致精确缺失
最近做工厂项目,测试提的一个bug在本地测了好久一直没复现;直接连测试线的数据库,又经过一系列流程模拟最终在本地复现了这个问题;由于有消息日志的定时输出,只能打点介入来追踪bug,最后发现问题出在对double列累加的SQL语句上,真是一顿好找。
百度‘mysql 设置double列累加’,发现精度缺失对于double类型是不可控的。网上都建议将表字段更换为decimal类型,对于上线已久或开发完成的项目而言,显然是不合适的,因为改了列的类型又会引发列取值问题。
由此,我根据本地已复现的bug做了如下测试;
新建一张表:
CREATE TABLE `test` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', `numDouble` double NOT NULL COMMENT 'double类型取值', `numDoubleLimit` double DEFAULT NULL COMMENT 'double类型精确取值', `numDecimal` decimal(10,5) NOT NULL COMMENT 'decimal精确取值', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
先插入一条数据:
INSERT INTO `test` (`id`, `numDouble`, `numDoubleLimit`, `numDecimal`) VALUES ('1', '0', '0', '0.00000');
执行以下SQL三次:
# double列累加
UPDATE test SET numDouble = numDouble + 192.2 WHERE id = 1;
# double列取约数后累加,double类型会在0后的剩余长度补足一些小数,而大概就是这些小数导致的double类型求和后精度缺失 UPDATE test SET numDoubleLimit = ROUND(numDoubleLimit + 192.2, 5) WHERE id = 1;
# decimal列累加 UPDATE test SET numDecimal = numDecimal + 192.2 WHERE id = 1; SELECT numDouble,numDoubleLimit,numDecimal FROM test;
发现结果如下:
解决方案:
double列取约数后再累加求和,问题解决!
由此,总结如下:
1、追查日志,在大项目中由于定时器任务等复杂业务,会导致打印大量的日志,如果没有关键日志就会很难追踪bug; 2、开发完的项目在测试线总会出现一些奇奇怪怪的问题,最好可以直接连测试环境直接复现问题,然后再逐一排除问题; 3、找到问题的前后逻辑,并联系'上下文',有利于确认问题位置、确定问题处理方案; 4、设计表的小数字段类型时,形如金额、收货数量等要求精度的属性时可以用decimal;如果担心decimal类型的列取值问题,也可以使用double类型,但是最好不要用SQL直接累加double列,建议在外层代码计算好double列值,SQL语句仅set保存double列的值
*代码中的double列求和精度缺失,请参考:
double a = 192.2D; double b = 0D; b += a; b += a; b += a; System.out.println(b);// 结果:576.5999999999999 BigDecimal aDecimal = new BigDecimal(Double.toString(192.2D)); BigDecimal bDecimal = new BigDecimal(Double.toString(0D)); bDecimal = bDecimal.add(aDecimal).add(aDecimal).add(aDecimal); System.out.println(bDecimal.doubleValue());// 结果:576.6
补充示例:
double a = 0.21; double b = 0.0; double c = 0.11; double d = a - b - c; System.out.println(d);// 0.09999999999999999 double e = 0.21 - 0 - 0.11; System.out.println(e);// 0.09999999999999999
雨淋淋过的季节
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!