最近项目从Mysql数据库换成了PostgressSQL导致以前用的很舒服的id自增不能用了,pgsql想自增还要创建序列比较麻烦,所以换成了UUID和雪花算法,因此遇到long类型id传递失真。
雪花算法生成的分布式ID长度为19位,前端JS接收数字能够达到的最大精度为16位,因此导致前端得到的ID不是真正的ID。
1、UUID
优点:对于所有的UUID它可以保证在时间和空间上的唯一性,它通过MAC地址,时间戳,命名空间,随机数,伪随机数来保证生成ID的唯一性,有着固定的大小(128bit)。它的唯一性和一致性特点使得可以无需注册过程就能够产生一个新的UUID。
缺点:UUID无序,且UUID在意外情况下(mac地址等其他生成UUID的因素相同的情况)可能会出现UUID相同,且存在隐私安全问题(mac地址)。
2、雪花算法SnowFlake
算法结构:符号位+时间戳+工作进程位+序列号位,一个64bit的整数,8字节,正好为一个long类型数据。
优点:所有生成的id按时间趋势递增,整个分布式系统内不会产生重复id。
缺点:由于雪花算法严重依赖时间,所以当发生服务器时钟回拨的问题是会导致可能产生重复的id。雪花算法的长度是19(long型最多19位)位的,前端能够接收的数字最多只能是16位的,因此就会造成精度丢失,得到的ID不是真正的ID。
解决方案
1、如果自身的项目可以修改id类型为String,那就用String类型代替
2、使用注解@JsonSerialize(using = ToStringSerializer.class),此方式的弊端就是要在每一个Entity类的字段上添加注解
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
@Data
public class Person {
/**
* 方式二:JsonSerialize注解
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
}
3、在拦截器中加入Long类型转换
@Configuration
@EnableWebMvc
public class InterceptorConfig implements WebMvcConfigurer {
/**
* 方式三:拦截器转换
*/
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = jackson2HttpMessageConverter.getObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
jackson2HttpMessageConverter.setObjectMapper(objectMapper);
converters.add(0, jackson2HttpMessageConverter);
}
}
4、ObjectMapper注入
@Configuration
public class JsonConfig{
/**
* 方式四:ObjectMapper注入
*/
@Bean
public ObjectMapper objectMapper (Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
return objectMapper;
}
}
以上!