在执行入库时,以防精度丢失大多人会擦用雪花算法生成字符串ID,可以从拦截器,yml全局配置等各方面去实现,下面将通过实现mybatisPlus的IdentifierGenerator 方式去实现。
自定义ID生成器,采用雪花机器算法
public class SnowflakeIdWorker {
/**
* 开始时间戳 (2020-01-01)
*/
private final long twepoch = 1609459200000L;
/**
* 序列号占的位数
*/
private final long sequenceBits = 12L;
/**
* 数据标识 ID 采用的位数
*/
private final long machineBits = 5L;
/**
* 数据中心 ID 采用的位数
*/
private final long datacenterBits = 5L;
/**
* 支持的最大机器 ID
*/
private final long maxMachineId = -1L ^ (-1L << machineBits);
/**
* 支持的最大数据中心 ID
*/
private final long maxDatacenterId = -1L ^ (-1L << datacenterBits);
/**
* 序列号最大值
*/
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
/**
* 机器 ID 左移位数
*/
private final long machineIdShift = sequenceBits;
/**
* 数据中心 ID 左移位数
*/
private final long datacenterIdShift = sequenceBits + machineBits;
/**
* 时间戳左移位数
*/
private final long timestampLeftShift = datacenterIdShift + datacenterBits + machineBits;
/**
* 上次生成 ID 的时间戳
*/
private long lastTimestamp = -1L;
/**
* 序列
*/
private long sequence = 0L;
/**
* 机器 ID
*/
private long machineId;
/**
* 数据中心 ID
*/
private long datacenterId;
/**
* 构造函数
*
* @param datacenterId 数据中心ID
* @param machineId 机器ID
*/
public SnowflakeIdWorker(long datacenterId, long machineId) {
// 检查 datacenterId 和 machineId 是否符合规定
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException("datacenterId can't be greater than " + maxDatacenterId + " or less than 0");
}
if (machineId > maxMachineId || machineId < 0) {
throw new IllegalArgumentException("machineId can't be greater than " + maxMachineId + " or less than 0");
}
this.datacenterId = datacenterId;
this.machineId = machineId;
}
/**
* 产生下一个 ID
*
* @return Long 类型的 ID
*/
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
// 如果当前时间戳小于上次生成 ID 的时间戳,则发生时钟回拨
if (timestamp < lastTimestamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id for " + (lastTimestamp - timestamp) + " milliseconds");
}
// 如果是同一毫秒内生成的 ID,序列号递增
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask; // 0 到 sequenceMask 之间循环
if (sequence == 0) {
// 如果序列号已用尽,等待下一毫秒
timestamp = waitNextMillis(lastTimestamp);
}
} else {
sequence = 0L; // 不同的时间戳重新开始生成
}
lastTimestamp = timestamp;
long id = ((timestamp - twepoch) << timestampLeftShift) // 时间戳部分
| (datacenterId << datacenterIdShift) // 数据中心 ID 部分
| (machineId << machineIdShift) // 机器 ID 部分
| sequence;
// 组合成一个 ID
return Math.abs(id);
}
/**
* 等待直到下一毫秒
*
* @param lastTimestamp 上次生成 ID 的时间戳
* @return 当前时间戳
*/
private long waitNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
private static class SnowflakeIdWorkerSingleton {
private static final SnowflakeIdWorker INSTANCE = new SnowflakeIdWorker(1L, 1L); // 可配置 datacenterId 和 machineId
}
public static SnowflakeIdWorker getInstance() {
return SnowflakeIdWorkerSingleton.INSTANCE;
}
public static void main(String[] args) {
long l = SnowflakeIdWorker.getInstance().nextId();
System.out.println(l);
}
}
实现IdentifierGenerator方法
public class StringSnowflakeIdGenerator implements IdentifierGenerator {
@Override
public Number nextId(Object entity) {
return SnowflakeIdWorker.getInstance().nextId();
}
@Override
public String nextUUID(Object entity) {
return String.valueOf(SnowflakeIdWorker.getInstance().nextId());
}
}
配置springIOC
@Configuration(proxyBeanMethods = false)
public class MybatisPlusPageConfigurer implements WebMvcConfigurer {
/**
* SQL 过滤器避免SQL 注入
* @param argumentResolvers
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new SqlFilterArgumentResolver());
}
/**
* 分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
/**
* 审计字段自动填充
* @return {@link MetaObjectHandler}
*/
@Bean
public MybatisPlusMetaObjectHandler mybatisPlusMetaObjectHandler() {
return new MybatisPlusMetaObjectHandler();
}
@Bean
public StringSnowflakeIdGenerator stringSnowflakeIdGenerator() {
return new StringSnowflakeIdGenerator();
}
}
配置字段
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class BSEntity implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id",type = IdType.ASSIGN_ID)
private String id;
@TableField(value = "create_by", fill = FieldFill.INSERT)
private String createBy;
@TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
private String updateBy;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
@TableField(value = "deleted", fill = FieldFill.INSERT)
private Integer deleted;
}
然后调用mybatisPlus框架的入库是机会自动生成字符串雪花ID