当前位置: 首页 > news >正文

记一次雪花算法 ID 精度丢失的Bug:前端接收到的 Long 被“四舍五入”了?

后端生成的 ID:1961005746230337538
前端收到的 ID:1961005746230337500
—— 少了 38?!这不是 Bug,是 JavaScript 的“安全整数”陷阱!

本文记录一次真实项目中因 雪花算法 ID 精度丢失 导致的线上问题,并给出彻底、可复用的解决方案。


🐛 问题现象:Long 类型在前后端传输中“变短”了

❌ 看似正常的后端代码

// 使用雪花算法生成 ID
@TableName("user")
public class User {@TableId(type = IdType.ASSIGN_ID)private Long id; // 1961005746230337538private String name;// getter/setter...
}

接口返回:

{"id": 1961005746230337538,"name": "Chaya"
}

前端接收到的数据

console.log(user.id); // 输出:1961005746230337500

末尾的 38 没了!被“四舍五入”了!

根本原因:JavaScript 的 Number 精度限制

  • JavaScript 的 Number 类型是 双精度浮点数(64-bit)
  • 它能安全表示的整数范围是:-2^53 + 1 到 2^53 - 1(即 ±9,007,199,254,740,991)。
  • 而雪花算法生成的 ID 通常是 19 位 Long,远超 JS 安全范围。
  • 浏览器在解析 JSON 时,会自动将大整数转换为 Number,导致精度丢失

📌 举例:1961005746230337538 超过 2^53,JS 无法精确表示,自动“对齐”到最近的可表示值 → 1961005746230337500

解决方案:后端将 Long 序列化为字符串!

核心思路

在 Spring Boot 返回 JSON 时,将所有 Long 类型字段自动序列化为字符串,避免前端解析时精度丢失。

配置方式

@Configuration
public class WebConfig extends WebMvcConfigurationSupport {@Beanpublic MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() {MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();ObjectMapper objectMapper = new ObjectMapper();SimpleModule simpleModule = new SimpleModule();simpleModule.addSerializer(Long.class, ToStringSerializer.instance);simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);objectMapper.registerModule(simpleModule);jsonConverter.setObjectMapper(objectMapper);return jsonConverter;}@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {converters.add(customJackson2HttpMessageConverter());super.addDefaultHttpMessageConverters(converters);}}

🔍 关键代码解析

SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);

作用:注册一个 Jackson 模块,告诉 ObjectMapper:

  • 所有 Long 和 long 类型,在序列化成 JSON 时,不要转成数字,而是转成字符串!

✅ 效果对比

类型原始 JSON修复后 JSON
Long ID"id": 1961005746230337538"id": "1961005746230337538"
前端接收❌ 精度丢失✅ 完整字符串,无损

其他解决方案对比

方案优点缺点
全局 Long 转 String(本文方案)一劳永逸,无需改实体类所有 Long 都变字符串
@JsonFormat(shape = JsonFormat.Shape.STRING)精准控制字段每个字段都要加,易遗漏
前端使用 BigInt不改后端兼容性差,JSON 不支持 BigInt
ID 返回为 String 类型类型安全实体类不“纯洁”,影响数据库映射

推荐:全局配置 + 按需排除(如某些计数字段仍保留 Long)

如果某些 Long 字段不需要转字符串(如 agecount),可以自定义序列化器:

public class CustomLongSerializer extends JsonSerializer<Long> {@Overridepublic void serialize(Long value, JsonGenerator gen, SerializerProvider serializers) throws IOException {// 根据字段名或注解判断是否转字符串if (isIdField(gen)) {gen.writeString(value.toString());} else {gen.writeNumber(value);}}
}

但大多数场景下,统一转字符串更简单可靠

http://www.dtcms.com/a/354820.html

相关文章:

  • Java HTTP 请求:Unirest 使用指南及与 HttpClient 对比
  • 数据湖与数据仓库
  • 「数据获取」25年最新安徽省路网数据安徽省路网分类数据(获取方式看绑定的资源)
  • 自动化三维测量仪工业零件自动外观三维测量-中科米堆CASAIM
  • 三维视频融合驱动视频孪生创新:智汇云舟引领数字孪生产业新范式
  • Kubernetes一EFK日志架构
  • 在 Ubuntu 24.04 上安装二进制文件(逐步指南)
  • HCIA备考知识点总结:第二章华为VRP系统知识点
  • 嵌入式学习日记(36)TCP并发服务器构建——epoll
  • leetcode算法刷题的第二十天
  • 力扣18:四数之和
  • CodeSouler v2.4.0 版本更新
  • 生成式推荐模型的长序列特征:离线存储
  • 超越文本:深入剖析多模态AI的架构原理
  • c++ 观察者模式 订阅发布架构
  • FFmpeg05:编解码实战
  • 机器学习框架下:金价近3400关口波动,AI量化模型对PCE数据的动态监测与趋势预测
  • 企业通讯软件以安全为基,搭建高效的通讯办公平台
  • RA4M2环境搭建与新建工程
  • 新手向:Python开发简易股票价格追踪器
  • Linux内核IPv4 RAW套接字深度解析:从数据包构造到可靠传输的挑战
  • Dify 和 LangChain 区别对比总结
  • 【实操教学】ArcGIS 如何进行定义坐标系
  • Python实现点云基于法向量、曲率和ISS提取特征点
  • 【GM3568JHF】FPGA+ARM异构开发板 使用指南:显示与触摸
  • 第二章:Cesium 视图控制与相机操作
  • Java集合操作:Apache Commons Collections4启示录
  • React中优雅管理CSS变量的最佳实践
  • iOS文件管理在uni-app开发中的实战应用,多工具解决
  • 三、计算机网络与分布式系统(上)