雪花Id(snowflake)主键(Long) ,前端丢失精度原理及解决之道

1、案例场景

我们项目之中可能大多数都使用自增长id作为主键id,这样对于中小型系统来说一般没有啥问题。但是随着各种业务发展以及后续可能分库分表情况;我们有些项目或者项目之中的独立微服务可能使用的是雪花算法生成的主键id(19位)长整型的。于是最近我们在项目对接其他微服务(使用的雪花主键id)之后,在前端调用接口之后发现返回结果id被裁减了。经过组内同事定位📌Long型精度损失。具体原因下面原理部分分析。

2、雪花(snowflake)Id,Long id前端精度损失原因

本人试验以及结合网上的文章,发现一个问题,在PostMan里面请求接口能够完全正确的返回雪花算法生成的主键id,但是在Swagger或者前端接口请求 浏览器之中就会出现雪花算法精度损失问题。于是查找原因如下:

​ ****JavaScript 不支持后台返回的 Long 类型,JavaScript 的 number 类型的数值范围是 -2^53~2^53(不包含边界) 所以大于 9007199254740991 的数****,进制转换会存在精度问题,而雪花ID生成的数值过大,导致 JavaScript 不能正常存储导致。

同时注意:建议雪花ID在数据库中使用 bigint 来存储,而不是使用 varchar;这样可以提高这样数据库的速度,使用索引的时候少一步字符串转换成数字的操作。

​ 于是我的实际项目之中返回的雪花算法的主键id

JavaScript的Number最大id*9007199254740991*
项目主键id1511972392982179840
浏览器或者swagger返回1511972392982179800

于是就出现了 前端传递的id,找寻不到对应的记录问题。

3、解决JavaScript Number长整型精度丢失问题

解决方案1

使用Jackson注解,我们也可以用@JsonFormat做类型转换

在VO类中,id上添加注释

@ApiModelProperty(name = "id", value = "消息id")



@JsonProperty("id")



//此句为问题关键 相当于吧Long转换为String



@JsonFormat(shape = JsonFormat.Shape.STRING)



@JSONField(serializeUsing = ToStringSerializer.class)



//此处标识得在序列化的时候转换为字符串



private Long id;

其他相关:

@JSONField(serializeUsing= ToStringSerializer.class)

这个注解是Fastjson的,旨在让系统系列化时,保留相关精度。

解决方案2

​ 写一个 JSON 配置类,将 Long 类型序列化成 JSON 的时候自动转为 String 类型

@Configuration



public class JacksonConfiguration {



 



    @Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}")



    private String pattern;



 



    @Bean



    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {



        return builder -> {



            // Long 会自定转换成 String



            builder.serializerByType(Long.class, ToStringSerializer.instance);



        };



    }



}

4、成果展现 img


已有 0 条评论

    欢迎您,新朋友,感谢参与互动!