1、IDWork
/**
* 版权: Copyright by ljm
* 描述: ID工具类
* 修改人: HuamingChen
* 修改时间:2020/3/31
* 跟踪单号:
* 修改单号:
* 修改内容:
*/
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("-", "");
}
}
2、序列
/**
* 版权: Copyright by ljm
* 描述:
* 修改人: HuamingChen
* 修改时间:2020/5/3
* 跟踪单号:
* 修改单号:
* 修改内容:
*/
import com.ljm.common.utils.AssertUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.concurrent.ThreadLocalRandom;
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) {
AssertUtil.isFalse(workerId > 31L || workerId < 0L, String.format("worker Id can't be greater than %d or less than 0", 31L));
AssertUtil.isFalse(datacenterId > 31L || datacenterId < 0L, String.format("datacenter Id can't be greater than %d or less than 0", 31L));
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();
}
}
3、systemLock
/**
* 版权: Copyright by ljm
* 描述:
* 修改人: HuamingChen
* 修改时间:2020/5/3
* 跟踪单号:
* 修改单号:
* 修改内容:
*/
import java.sql.Timestamp;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
public class SystemClock {
private final long period;
private final AtomicLong now;
private SystemClock(long period) {
this.period = period;
this.now = new AtomicLong(System.currentTimeMillis());
this.scheduleClockUpdating();
}
private static SystemClock instance() {
return SystemClock.InstanceHolder.INSTANCE;
}
public static long now() {
return instance().currentTimeMillis();
}
public static String nowDate() {
return (new Timestamp(instance().currentTimeMillis())).toString();
}
private void scheduleClockUpdating() {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor((runnable) -> {
Thread thread = new Thread(runnable, "System Clock");
thread.setDaemon(true);
return thread;
});
scheduler.scheduleAtFixedRate(() -> {
this.now.set(System.currentTimeMillis());
}, this.period, this.period, TimeUnit.MILLISECONDS);
}
private long currentTimeMillis() {
return this.now.get();
}
private static class InstanceHolder {
public static final SystemClock INSTANCE = new SystemClock(1L);
private InstanceHolder() {
}
}
}
4、说明改工具类,是从mybatis-plus中复制的。只是简单的抽取成自己的工具类。勿喷。不过这工具会随着部署容器的影响,导致数据中心出现一致的情况,从而导致主键冲突的可能性增加。
有其他好方案的朋友,分享一下。谢谢大家。