SpringBoot雪花ID长数字Long类型精度丢失

文章讨论了在使用雪花ID作为Long类型主键时遇到的精度丢失问题,尤其是在数据传输到前端时超过JS最大值。解决方案包括后端将Long转换为String序列化,以及前端使用JSONbig库对大数字进行安全处理。提供了具体的Java和Vue实现代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Long类型精度丢失

最近项目中使用雪花ID作为主键,雪花ID是19位Long类型数字,数据返回到前端会出现精度丢失问题,数字已经超过了前端浏览器或JS的最大值。

Java后端数据模型

请添加图片描述

返回到浏览器后的数据模型,前后数据不一致

请添加图片描述

解决方式一:后端处理

序列化时将Long类型转成String类型

1、在启动类中加 @JsonComponent 注解
2、再在启动类中加上以下代码

    @Bean
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        //忽略value为null 时 key的输出
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        /**
         * 序列换成json时,将所有的long变成string
         * 因为js中得数字类型不能包含所有的java long值
         */
        SimpleModule module = new SimpleModule();
        module.addSerializer(Long.class, ToStringSerializer.instance);
        module.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(module);
        return objectMapper;
    }

方式二 前端处理(Vue)

在前端使用JSONbig将大数字做安全处理

1、在package.json中引入JSONbig, “json-bigint”: “^1.0.0” ,执行npm install命令
请添加图片描述
2、在requesst.js中创建axios实例时增加代码处理,(重点)导入JSONbig和添加transformResponse属性,相当于拦截器,请求相应后处理先处理一下。

//导入JSONbig
import JSONbig from 'json-bigint'
// 在创建axios实例中增加transformResponse属性
const service = axios.create({
  // axios中请求配置有baseURL选项,表示请求URL公共部分
  baseURL: process.env.VUE_APP_BASE_API,
  transformResponse: [function(data) {
    try {
      // 作用1:把json字符串转为js对象
      // 作用2:把里面的大数字做安全处理
      return JSONbig.parse(data)
    } catch (e) {
      return data
    }
  }],
  // 超时
  timeout: 10000
})

请添加图片描述

求关注、求点赞~~~

点关注不迷路,喜欢的朋友们关注支持一下
给点继续写的动力,感谢!!
### Spring Boot 中实现雪花算法生成唯一 IDSpring Boot 应用程序中集成雪花算法来生成唯一的全局 ID 是一种常见做法。通过这种方式可以确保即使在高并发场景下也能快速可靠地获取到不重复的 ID。 #### 雪花算法简介 SnowFlake 算法由 Twitter 提出,采用了一个 64bit 的 Long 类型数据结构用于表示唯一 ID[^2]。具体位分配如下: | 字段 | 描述 | | --- | --- | | 符号位 (1 bit) | 总是0, 表示正数 | | 时间戳 (41 bits) | 记录毫秒级时间偏移量 | | 数据中心ID (5 bits) | 支持最多31个数据中心 | | 工作机器ID (5 bits) | 同一数据中心内支持最多31台服务器 | | 自增序列号 (12 bits) | 单机每毫秒内的计数值 | 这种设计使得生成出来的 ID 不仅具有全局唯一性而且还能保持一定顺序特性,在数据库索引方面表现良好。 #### 实现步骤 为了方便开发者使用,这里提供了一种基于 Java 编写的 SnowflakeIdWorker 类实现方式,并将其封装成工具类以便于调用。 ```java package com.example.demo.utils; import org.springframework.stereotype.Component; @Component public class IdGenerator { private final static long twepoch = 1288834974657L; // 起始的时间戳 private final static int workerIdBits = 5; private final static int datacenterIdBits = 5; private final static long maxWorkerId = ~(-1L << workerIdBits); private final static long maxDataCenterId = ~(-1L << datacenterIdBits); private final static int sequenceBits = 12; private final static long workerIdShift = sequenceBits; private final static long datacenterIdShift = sequenceBits + workerIdBits; private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; private final static long sequenceMask = ~(-1L << sequenceBits); private long workerId; private long datacenterId; private long sequence = 0L; private long lastTimestamp = -1L; public IdGenerator(long workerId, long datacenterId){ if(workerId > maxWorkerId || workerId < 0){ throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0",maxWorkerId)); } if(datacenterId > maxDataCenterId || datacenterId < 0){ throw new IllegalArgumentException(String.format("data center Id can't be greater than %d or less than 0",maxDataCenterId)); } this.workerId = workerId; this.datacenterId = datacenterId; } protected synchronized long nextId(){ long timestamp = timeGen(); if(timestamp < lastTimestamp){ try{ throw new Exception("Clock moved backwards. Refusing to generate id"); }catch(Exception e){ System.err.println(e.getMessage()); } } if(lastTimestamp == timestamp){ sequence = (sequence + 1) & sequenceMask; if(sequence == 0){ timestamp = tilNextMillis(lastTimestamp); } }else{ sequence = 0L; } lastTimestamp = timestamp; return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; } private long tilNextMillis(final long lastTimestamp){ long timestamp = timeGen(); while (timestamp <= lastTimestamp){ timestamp = timeGen(); } return timestamp; } private long timeGen(){ return System.currentTimeMillis(); } } ``` 上述代码实现了基本的雪球算法逻辑并提供了 `nextId()` 方法用来获取新的唯一 ID。需要注意的是实际部署时还需要考虑跨节点同步等问题以防止冲突发生。 对于 Spring Boot 应用来说可以直接注入此组件并通过方法调用来获得所需 ID: ```java @Autowired private IdGenerator idGenerator; // 使用地方直接调用即可得到新id Long uniqueId = idGenerator.nextId(); ``` 此外还可以进一步优化该方案比如引入 Redis 或 Zookeeper 来管理 Worker 和 Data Center IDs 分配从而更好地适应大规模集群环境下的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乾坤鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值