侧边栏壁纸
  • 累计撰写 9 篇文章
  • 累计创建 4 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

踩坑记录之雪花ID丢失精度问题

Dckxx
2024-12-05 / 0 评论 / 0 点赞 / 12 阅读 / 2843 字

问题描述

在数据库层面对于表的 ID 字段选择使用了 bigint 这种数据类型, 而在与之对应的 Java 实体类里,将这个 ID 的属性的数据类型设定为 Long。在新增数据的操作过程中,采用了雪花 ID 作为主键生成策略。雪花 ID 是一种被广泛应用的、能够保证分布式环境下生成唯一标识符的算法,它生成的 ID 具有特定的格式和长度,在我们当前的应用场景中,其生成的 ID 长度达到了 18 位。

导致原因

当我们执行查询数据的操作时,就出现了精度丢失的问题。这是因为在 Java 中,Long 类型是继承自 number 类的。而 number 类自身存在着一定的精度限制,其规定的精度为 16 位。这就意味着,当我们试图将长度为 18 位的雪花 ID(由雪花 ID 主键策略所生成)赋值给 Long 类型的属性时,由于 Long 类型背后所依托的 number 类精度不够,无法完整容纳这么长的数据,最终只能截取前面 16 位,从而导致了后面 2 位精度的丢失。

举个例子,假设生成的一个雪花 ID 为 “123456789012345678”(这里只是示例格式,实际的雪花 ID 有其特定的编码规则和含义),当把它赋值给实体类中 Long 类型的 ID 属性时,因为 number 类 16 位精度的限制,最终实际存储在 Long 类型属性里的值可能就变成了 “1234567890123456”,后面两位 “78” 就丢失了,进而可能引发后续一系列与数据准确性相关的问题,比如在基于这个 ID 进行数据关联、展示或者其他业务逻辑处理时,由于 ID 值已经不准确,就可能出现查询不到对应准确数据、数据关联错误等情况,对整个系统的数据完整性和业务流程的正确执行产生不良影响。

解决方案

方式一: 局部设置

在实体类中, 我们可以给ID属性的字段添加注解

@JsonFormat(shape=JsonFormat.Shape.STRING)

方式二: 全局设置

可以在整个项目中新增一个配置类, 使用序列化的方式专门来处理从数据库查询出来的数据转成对应实体类的属性

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

@Configuration
public class JacksonConfig {

    @Bean
    @Primary
    @ConditionalOnMissingBean(ObjectMapper.class)
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();

        // 全局配置序列化返回 JSON 处理
        SimpleModule simpleModule = new SimpleModule();
        //JSON Long ==> String
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }

}

0

评论区