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

java数据类型:Long 和 long 在雪花算法ID下的陷阱

Longlong在雪花算法ID(19位长整型)下的坑,或者前端JS解析后端Long精度丢失的问题,是中国互联网公司线上事故的高发区,尤其是涉及分布式ID和前后端对接时。我挨个给你拆解,附带真实故障场景。

第一坑:Long 和 long 在雪花算法ID下的陷阱

1. 背景知识:雪花算法ID有多长?

雪花算法(Snowflake)生成的ID是一个64位(bit)的Long型数字,通常由:

  • 1位符号位(固定0)

  • 41位时间戳(可用69年)

  • 10位机器ID

  • 12位序列号(同一毫秒内可生成4096个ID)

最终结果:一个类似1478733705032859648的数字,长度是19位

2. 陷阱一:用long接收没问题,但计算会溢出?

结论:用long接收19位ID完全没问题(Long.MAX_VALUE ≈ 9.22e18,19位数字最大约9.9e18,在范围内)。

真正的坑在于:如果你不小心用了Long包装类,在做算术运算时自动拆箱,如果对象是null,就会抛NullPointerException。所以ID字段强烈建议用long(基本类型),因为它永不可能是null(数据库主键必有值)。

3. 陷阱二:数据库类型选错(致命!)

数据库类型最大值能否存19位雪花ID?
MySQL INT21亿(约2.1e9)❌ 存不下,截断或报错
MySQL BIGINT9.22e18✅ 完美支持
Oracle NUMBER(19)19位✅ 完美支持

真实事故:某小公司用INT存雪花ID,当ID超过21亿时,数据插入直接报错Out of range,线上订单无法创建,紧急改表结构才恢复。

解决方案:建表时务必用BIGINT

sql

CREATE TABLE orders ( id BIGINT PRIMARY KEY, -- 不是 INT! order_no VARCHAR(64) );

第二坑:前端JS解析后端Long精度丢失(高频线上事故)

这是最经典的坑,90%的互联网公司都踩过。

1. 问题根源:JS的数字精度限制

  • Java 的Long最大值:9223372036854775807(19位)

  • JavaScript 的Number类型是双精度浮点数,安全整数范围只有:

    • -(2^53 - 1)(2^53 - 1)

    • 即:-9007199254740991900719925474099116位

结论:当后端返回的19位雪花ID超过9007199254740991时,JS解析会丢失精度

2. 真实事故演示

后端(Java)返回JSON:

json

{ "id": 1478733705032859648, "userName": "张三" }

前端(JS)接收后:

javascript

const data = JSON.parse('{"id": 1478733705032859648, "userName": "张三"}'); console.log(data.id); // 输出:1478733705032859600 (最后两位变成了00,精度丢失了!)

后果:

  • 前端用这个ID去查询详情 → 查不到数据

  • 前端用这个ID去更新 → 更新了错误的数据

  • 前端用这个ID做删除 → 删错了记录

3. 解决方案(3种主流做法)

方案一:后端转为字符串返回(最常用、最稳妥)

思路:后端在序列化时,将Long类型的ID自动转为String。

Spring Boot + Jackson 全局配置:

java

@Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); // 将所有Long类型序列化为String module.addSerializer(Long.class, ToStringSerializer.instance); module.addSerializer(Long.TYPE, ToStringSerializer.instance); mapper.registerModule(module); return mapper; } }

返回结果:

json

{ "id": "1478733705032859648", // 变成了字符串! "userName": "张三" }

前端拿到字符串,直接使用,不会丢失精度。

方案二:前端使用 BigInt(ES2020新特性)

JS原生支持BigInt类型,可以精确表示任意大整数。

javascript

// 后端返回字符串,前端转BigInt const id = BigInt("1478733705032859648"); console.log(id); // 1478733705032859648n

缺点:浏览器兼容性要求较高(Chrome 67+),且JSON.parse默认不会自动转BigInt。

方案三:使用注解局部控制(精细化)

如果不想全局改,可以用注解单独指定某个字段:

java

@JsonSerialize(using = ToStringSerializer.class) private Long id; // 只有这个字段转字符串

4. 数据库查询时的坑(补充)

如果你用Long id作为查询条件,前端传过来的是字符串"1478733705032859648",Spring MVC 能自动转成Long但前提是:前端传的字符串不能超过Long.MAX_VALUE,否则会报NumberFormatException

解决办法:将Controller入参也改为String,然后手动转:

java

@GetMapping("/order/{id}") public Result getOrder(@PathVariable String id) { // 如果需要,转成Long(但推荐直接用String查数据库,BIGINT支持字符串比较) return service.getOrder(id); }

终极总结(一张表解决所有疑问)

场景推荐方案原因
实体类ID字段long(基本类型)绝对不可能为null,避免拆箱NPE
数据库ID字段BIGINT支持19位雪花ID
后端返回给前端转为String避免JS精度丢失
前端使用ID当作字符串处理不要转成Number,直接传给后端
Controller入参String接收避免超长导致转换异常

生产环境最佳实践(直接抄作业)

Entity类:

java

public class Order { private long id; // 基本类型,永不null private Long userId; // 外键可能为null,用包装类 }

Controller:

java

@GetMapping("/order/{id}") public Result getOrder(@PathVariable String id) { // 用String接收 // 调用Service时,如果需要可以转为long return orderService.getById(Long.parseLong(id)); }

Jackson配置(全局转String):

java

@Configuration public class WebConfig { @Bean public Jackson2ObjectMapperBuilderCustomizer customizer() { return builder -> { builder.serializerByType(Long.class, ToStringSerializer.instance); builder.serializerByType(long.class, ToStringSerializer.instance); }; } }

数据库DDL:

sql

CREATE TABLE `order` ( `id` BIGINT PRIMARY KEY COMMENT '雪花ID', -- 不是INT! `user_id` BIGINT COMMENT '用户ID', ... ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

最后送你一句保命箴言:

只要你的系统用了分布式ID(雪花、美团Leaf、滴滴Tinyid),立即检查前端是否把ID当数字用,如果是,马上改!这个坑99%的新人都会踩,线上故障通常发生在系统运行半年后、ID长度超过16位时。🛑

http://www.jsqmd.com/news/1185053/

相关文章:

  • Java语言中的类
  • 多态与虚函数:面试官问“底层怎么实现的”,这样答直接拿满分
  • static关键字的四种用法:面试官问“static有几种用法”,90%的人答不全
  • Unity XR开发入门:从SDK导入到交互配置的完整指南
  • CSS字体样式(font)[实战指南]
  • 亲身探访广州泰格豪雅官方售后服务中心|详细网点地址与售后热线(2026年7月最新) - 亨得利官方服务中心
  • Unity BlendShape与Animation Clip实现角色动态表情完整指南
  • 2026年7月最新温州劳力士官方售后客服中心地址电话及服务网点分布 - 劳力士官方服务中心
  • 卫星视频目标跟踪:从相关滤波到深度学习的演进与挑战
  • Folium地图可视化实战:从数据到交互式地理看板
  • 宝珀手表网上预订售后保养服务指南权威公示(2026年7月最新) - 宝珀官方售后服务中心
  • Pandas数据清洗速查手册:12个高频函数实战指南
  • Gifski跨平台视频转GIF终极指南:高质量转换与自动化脚本
  • 基于C++20协程的异步网络编程:libfv框架解析与实践指南
  • YOLOv8道路坑洼检测实战:从数据到部署全流程解析
  • 图像锐度评分算法实战:从方差、点锐度到梯度法的选择与优化
  • C++跨平台开发中整数类型陷阱与<cstdint>解决方案
  • 劳力士中国官方售后服务中心|全部网点地址及24小时热线权威信息通告(2026年7月更新) - 劳力士服务中心
  • 如何基于用户需求生成高质量技术博文
  • 2026最新衡水本地漏水检测公司本地精选权威推荐:正规防水补漏公司优选口碑TOP5:卫生间/厨房/阳台/飘窗/地下室渗漏水维修师傅上门 - 即刻修防水
  • Unity游戏开发:3分钟实现角色轮廓高亮效果(Outline Effect)
  • 2026年7月行业内诚信的巴伦公司推荐,功率电感RH系列/磁胶NR电感/车规电感/排磁珠/耦合器,巴伦实力厂家有哪些 - 品牌推荐师
  • Level 2行情数据下载过程和笔记
  • `beautifulsoup4`(简称 BeautifulSoup)是 Python 中最常用、最强大的 HTML 和 XML 解析库之一
  • AI学术写作工具核心功能与实操指南
  • 从洛谷P2234看平衡树实战:STL set与手写Treap解决动态查询
  • C++信号与槽机制:从原理到原生实现,构建松耦合对象通信系统
  • UU远程多屏协助测评,好不好看这个就够了、
  • Sol2:现代C++与Lua交互的零开销绑定库实战指南
  • ICM-42605与PIC18F2682实现高精度运动追踪方案