数字精度问题

问题描述

今天在修改一个系统日志功能时,发现我接口返回给前端的数据中出现了重复的日志ID:

重复ID
后端使用 spring-data-mongodb 将日志数据保存到 mongodb 中,日志记录的ID采用 java.lang.Long 类型定义,保存日志是通过 Snowflake 算法生成的全局唯一ID;

在这里插入图片描述


原因分析:

首先怀疑是数据库保存数据问题,先通过重复的日志ID到数据库查询日志信息:
在这里插入图片描述
这里查询出来的ID居然不一样,懵逼…, 再修改一下ID,还是查出来同一条记录:
在这里插入图片描述在这里插入图片描述
明明ID不一样但是的确能查询出来,后三位数字无论怎么修改查询结果都不影响,想不通…,然后我开始怀疑是不是ID不能用java.lang.Long 类型,后来通过单元测试模拟了一条日志保存和查询,居然没有问题,ID 保存到 mongodb 前的值和查询出来的值是一致的。
再次查看接口的返回数据(响应栏),ID并没有重复,但是通过预览栏查看为什么是重复的呢?突然想到好像JS中的数字是Number类型,使用IEEE754格式来表示整数和浮点值,这里的ID为19位数字,应该是丢失了精度。
在这里插入图片描述
既然前端JS不支持Long类型数字,那就将Long转换为String返回给前段,只需要在Id属性上添加 @JsonFormat(shape = JsonFormat.Shape.STRING) 注解就OK啦
在这里插入图片描述

再来看看mongodb根据ID查询的问题:mongodb中默认数字类型也是浮点数类型,所有上面我们的查询中的查询条件 1552841301425262600 丢失精度后为 1552841301425262590,mongodb 在执行查询过程中应该会把数据库中的ID属性转换为和查询条件相同的数据类型,而数据库中的记录ID 1552841301425262593 丢失精度后也为 1552841301425262590,所以能查询出来,
在这里插入图片描述
正确的查询条件应该为:NumberLong(“1552841301425262592”)
在这里插入图片描述
在这里插入图片描述


终结:

  • 前端JS不支持Long类型数字,返回给前端Long类型数据时需要转换为String
  • mongodb中默认数字类型也是浮点数类型,在查询数据时要注意属性类型
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值