public class IdWorker {
private static Sequence WORKER = new Sequence();
public static final DateTimeFormatter MILLISECOND = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
public IdWorker() {
}
public static long getId() {
return WORKER.nextId();
}
public static String getIdStr() {
return String.valueOf(WORKER.nextId());
}
public static String getMillisecond() {
return LocalDateTime.now().format(MILLISECOND);
}
public static String getTimeId() {
return getMillisecond() + getId();
}
public static void initSequence(long workerId, long datacenterId) {
WORKER = new Sequence(workerId, datacenterId);
}
public static String get32UUID() {
ThreadLocalRandom random = ThreadLocalRandom.current();
return (new UUID(random.nextLong(), random.nextLong())).toString().replace("-", "");
}
}
public class Sequence {
private static final Log logger = LogFactory.getLog(Sequence.class);
private final long twepoch = 1288834974657L;
private final long workerIdBits = 5L;
private final long datacenterIdBits = 5L;
private final long maxWorkerId = 31L;
private final long maxDatacenterId = 31L;
private final long sequenceBits = 12L;
private final long workerIdShift = 12L;
private final long datacenterIdShift = 17L;
private final long timestampLeftShift = 22L;
private final long sequenceMask = 4095L;
private final long workerId;
private final long datacenterId;
private long sequence = 0L;
private long lastTimestamp = -1L;
public Sequence() {
this.datacenterId = getDatacenterId(31L);
this.workerId = getMaxWorkerId(this.datacenterId, 31L);
}
public Sequence(long workerId, long datacenterId) {
Assert.isFalse(workerId > 31L || workerId < 0L, String.format("worker Id can't be greater than %d or less than 0", 31L), new Object[0]);
Assert.isFalse(datacenterId > 31L || datacenterId < 0L, String.format("datacenter Id can't be greater than %d or less than 0", 31L), new Object[0]);
this.workerId = workerId;
this.datacenterId = datacenterId;
}
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuilder mpid = new StringBuilder();
mpid.append(datacenterId);
String name = ManagementFactory.getRuntimeMXBean().getName();
if (StringUtils.isNotEmpty(name)) {
mpid.append(name.split("@")[0]);
}
return (long)(mpid.toString().hashCode() & '\uffff') % (maxWorkerId + 1L);
}
protected static long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
if (network == null) {
id = 1L;
} else {
byte[] mac = network.getHardwareAddress();
if (null != mac) {
id = (255L & (long)mac[mac.length - 1] | 65280L & (long)mac[mac.length - 2] << 8) >> 6;
id %= maxDatacenterId + 1L;
}
}
} catch (Exception var7) {
logger.warn(" getDatacenterId: " + var7.getMessage());
}
return id;
}
public synchronized long nextId() {
long timestamp = this.timeGen();
if (timestamp < this.lastTimestamp) {
long offset = this.lastTimestamp - timestamp;
if (offset > 5L) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
}
try {
this.wait(offset << 1);
timestamp = this.timeGen();
if (timestamp < this.lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
}
} catch (Exception var6) {
throw new RuntimeException(var6);
}
}
if (this.lastTimestamp == timestamp) {
this.sequence = this.sequence + 1L & 4095L;
if (this.sequence == 0L) {
timestamp = this.tilNextMillis(this.lastTimestamp);
}
} else {
this.sequence = ThreadLocalRandom.current().nextLong(1L, 3L);
}
this.lastTimestamp = timestamp;
return timestamp - 1288834974657L << 22 | this.datacenterId << 17 | this.workerId << 12 | this.sequence;
}
protected long tilNextMillis(long lastTimestamp) {
long timestamp;
for(timestamp = this.timeGen(); timestamp <= lastTimestamp; timestamp = this.timeGen()) {
;
}
return timestamp;
}
protected long timeGen() {
return SystemClock.now();
}
}
MyBatis-Plus默认使用策略,数据库中表的结构会发生变化,维护上一个主键的值,此值长达19位,数值型序列化给前端会有精度丢失,末三位都会变成0。
我在项目中遇到的问题,在开发前期使用的数据库自增策略,在联调阶段将此策略改为ASSGN_ID(雪花算法)后,前端联调时发现,请求的数据末尾三位都变成了0(前端数值型存在精度问题JS最大数值),报参数异常错误,自己打开浏览器的Network查看id时发现此问题。想着立马改回数据自增,再重新创建数据,此时已然无法进行编辑、删除等操作,已然报参数异常,查看数据库发现,是自增但是数很大,在自动递增的数上自增。在网上找了些帖子后来发现问题在此处!此时需要用回自增模式,方式一:修改表结构,重新指定自动递增的值;方式二:重新创建表!
当代码里再将主键策略制定为IdType.AUTO,数据库自增时,会在纪录的自动递增值上加1!