记录一个前段时间使用雪花算法时候遇到的坑。

场景大概是这样的:
我有一个设备信息实体类,设备id是 long 类型,映射到数据库中是一个设备表,主键id是 bigint 类型。id的生成策略是使用雪花算法。

使用postman调用接口,获取到的JSON是正常的

"id" : 1297873308628307970 , //其他属性省略

但是到了前端那边id的值却变成了1297873308628300000
仔细一比较发现这两个数值还挺像的,只有后4位不一样,当时立马想到了是不是精度丢失。
那么在哪个环节丢失了精度?用postman获取JSON的时候,数值是正常的,那么肯定不是后端丢失了精度,只可能是前端那边丢失了精度。

上网查了下, JSON字符串转JS对象,JSON中的数字会转为 number 类型, number 类型的精度是16位,但是雪花算法生成的id长度有19位,so后面的几位精度就丢失了 。如果想要前端不丢失精度,JSON中的id就不能是long类型,改为String类型就好了。

问题找到了,但要怎么解决呢。一种方案是修改实体类中id的类型,将id改为String类型,并且将表的主键也改为varchar类型。但是字符串查询性能比数字差,所以这种方案不太推荐。

好在Jackson已经为我了提供了 三种方案
一种是直接在实体类的id属性上面加上注解 @JsonSerialize(using = ToStringSerializer.class)
这样一来,在后端依然是 long 类型,当实体类序列化成JSON的时候,在JSON中这个属性就会变成string类型。

上面这种办法有个缺点就是,如果有很多的实体类的id都是 long 类型,那就得给每一个都加上注解,这样未免有些麻烦。下面这个方法通过添加一个全局配置来使long类型转为JSON中的string类型,省去了一个一个添加注解的麻烦。

@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;

第三种办法是在application.yml中加上以下配置,这个办法会将所有数字都变成字符串,包括longint 类型

spring:
  jackson:
    generator:
      writeNumbersAsStrings: true
                    记录一个前段时间使用雪花算法时候遇到的坑。场景大概是这样的:我有一个设备信息实体类,设备id是 long 类型,映射到数据库中是一个设备表,主键id是 bigint 类型。id的生成策略是使用雪花算法。使用postman调用接口,获取到的JSON是正常的{  "id": 1297873308628307970,  ...  //其他属性省略}但是到了前端那边id的值却变成了1297873308628300000仔细一比较发现这两个数值还挺像的,只有后4位不一样,当时立马想到了是不是精度
				
问题描述: 后端把Long类型的数据前端前端可能出现精度丢失的情况。例如:201511200001725439这样一个Long类型的整数,前端变成201511200001725440 解决方法: 把Long类型再回时强转为String 通过@JsonSerialize注解自动转换 这里主要描述第二种方法如何实现 只需要转换的字段加上注解,并指定using为 ToStringSerializer.class @JsonSerialize(using = ToStringSerialize
1. 什么是Redis?它主要用来什么的? Redis,英文全称是 Remote Dictionary Server(远程字典服务),是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。 与MySQL数据库不同的是,Redis的数据是存在内存中的。它的读写速度非常快,每秒可以处理超过10万次读写操作。因此redis被 广泛应用于缓存,另外,Redis也经常用来做分布式锁。除此之外,Redis支持事务、持久化、LUA 脚本、L
场景:从数据库中查找出一条记录,返回为A对象,A对象的id变量为Long类型,该id为1373995515313754114。现在控制器接收一个Long类型的参数demandId同样为1373995515313754114,此时在Service层有个条件判断恰好是要比较A.id与demandId是否相当。这个时候条件反应使用了if(A.id == demandId);该条件判断即使是两个是相等的也返回false。 原因:Long类型是包装类型,==比较符号比较的是两个对象的地址,从而导致始终返回
在 Redis 中将 long 类型转换为 string 存入 hash 时,可能出现精度丢失的情况。解决方法是在存入和取出时使用数字字符串,而不是直接使用 long 类型。 例如,在存入时将 long 转换为字符串: long num = 1234567890; String numString = Long.toString(num); redisTemplate.opsForHash().put("hash_name", "field_name", numString); 在取出时将字符串转换为 long: Object value = redisTemplate.opsForHash().get("hash_name", "field_name"); long num = Long.parseLong((String)value); 总之,从Redis里存取long时,转成字符串存取,获取时再转成long类型即可避免精度丢失he_sk: ArrayBlockingQueue添加元素更快,因为它只是要要保存的对象的引用放到数组对应位置,而LinkedBlockingQueue需要创建一个Node对象;同时在获取后这个Node对象变成了垃圾,在读写很大的情况会多出很多垃圾,可能会影响程序的性能; 基于数组的ArrayBlockingQueue读写速度比基于链表的LinkedBlockingQueue更快??? 理解Spring定时任务@Scheduled的两个属性fixedRate和fixedDelay 抑郁的孤狼: