JSON数据存储精度异常:88.98存入数据库变为88.9800033569336求修正方案
解决浮点数精度丢失导致的数据库存储偏差问题
嘿,这个问题我之前碰过好多次——本质就是二进制浮点数的精度缺陷在作祟。像88.98这类十进制小数,没法用FLOAT/DOUBLE这类二进制浮点数类型精确存储,存进数据库后就会出现这种莫名其妙的尾数位偏差。下面是几个能彻底解决或者有效缓解的方案:
改用定点数类型存储(最优方案)
这是从根源解决问题的办法:- 数据库侧:把存储股价的字段类型从FLOAT/DOUBLE改成
DECIMAL(总位数, 小数位数),比如业务要求两位小数的话,就定义成DECIMAL(10,2)(总位数可以根据业务调整,确保能容纳最大的股价数值)。DECIMAL是用十进制存储的,完全不会有二进制转换的精度损失。 - 代码侧:接收JSON里的
baseYearStockPrice字符串时,直接转换成BigDecimal(Java)、Decimal(Python)这类定点数类型,再存入数据库,全程避免用浮点数类型中转。
- 数据库侧:把存储股价的字段类型从FLOAT/DOUBLE改成
精确解析字符串数值
如果暂时没法改数据库字段类型(不推荐,但特殊场景下可以用),在把JSON的字符串转成数值时,一定要用十进制精确解析:- 比如Java里用
new BigDecimal("88.98")替代Double.parseDouble("88.98");Python里用decimal.Decimal("88.98")代替float("88.98"),再把转换后的数值存入数据库,能最大程度减少精度丢失。
- 比如Java里用
入库前做精确的小数位处理
要是因为历史架构限制没法改字段类型,退而求其次的办法是在数据入库前,对数值做严格的两位小数处理:- SQL层面:插入时用
ROUND(?, 2)函数把数值保留两位小数后再存储; - 代码层面:用BigDecimal的
setScale(2, RoundingMode.HALF_UP)(四舍五入)或者其他符合业务规则的舍入模式,处理后再写入数据库。不过这个方案只是“修正”结果,不如定点数彻底解决问题。
- SQL层面:插入时用
从源头控制输入精度
在API接口或者前端层面加校验规则,确保POST过来的baseYearStockPrice是符合业务要求的格式(比如最多两位小数),避免非预期的高精度数值进入系统,从源头减少这类问题的发生。
内容的提问来源于stack exchange,提问作者Bijay Singh
相关产品推荐
相关产品推荐

