网站首页 > java教程 正文
这个也没啥讲的,上数据库集群,要是按照
数据库实例1:表ID初始值1,步长3;
数据库实例2:表ID初始值2,步长3;
数据库实例3:表ID初始值3,步长3;
的设置,可以解决ID重复问题,只是要再加一台就不好办了。
还有就是通过Redis的incr自增,因为是原子操作,也可以保证ID不重复。
再有就是zookeeper的持久顺序节点,也可以。
接着就是要说的雪花算法。
生成的ID是一个Long型数字,结构是:
0~时间戳42位(当前时间-开始时间)~数据中心ID5位~机器ID5位~序列号12位
0是符号位,代表正数。
如果我们实际中没有数据中心的概念,可以把机器ID扩充为10位。
另外多说一句,服务端回传Long给前端页面,JS处理Long会损失精度,所以服务端应该将Long转为String再回传。
同一服务集群部署,配置不同数据中心ID和机器ID即可。
/**
* 雪花分布式ID生成器 0~时间戳42位~数据中心ID5位~机器ID5位~序列号12位
*
*/
public class SnowFlakeUtils {
private int dcId;// 数据中心ID,0~31
private int mId;// 机器ID,0~31
private long lastTime = -1L;// 上一次时间戳
private long seq = 0L;// 序列号
private static final long START_TIME = 1603524605577L;// 最初时间戳
/**
* @param dcId 数据中心ID
* @param mId 机器ID
*/
public SnowFlakeUtils(int dcId, int mId) {
// 如果没有数据中心,可以直接把10位都给机器ID,0~1023
super();
if (dcId > 31 || dcId < 0) {
throw new IllegalArgumentException("数据中心ID范围0~31");
}
if (mId > 31 || mId < 0) {
throw new IllegalArgumentException("机器ID范围0~31");
}
this.dcId = dcId;
this.mId = mId;
}
public synchronized long getId() {
long now = Instant.now().toEpochMilli();
if (now < lastTime) {
return -1;
}
if (now == lastTime) {
// 时间相同,序号自增
seq = (seq + 1) & 4095;
if (seq == 0) {
// 如果本毫秒内,序列号已经是4095,+1&之后就会变成0,序列号重复。
// 通过将时间戳向后挪来解决。
now = this.getNextTime();
}
} else {
// 时间不同,序列号置为0
seq = 0L;
}
lastTime = now;
long id = (now - SnowFlakeUtils.START_TIME) << 22// 时间戳左移22位
| dcId << 17// 数据中心ID左移17位
| mId << 12// 机器ID左移12位
| seq;
return id;
}
/**
* 获取下一时间,如果时间<=上一次时间戳,则继续往后获取
*
* @return
*/
private long getNextTime() {
long now = Instant.now().toEpochMilli();
while (now <= lastTime) {
now = Instant.now().toEpochMilli();
}
return now;
}
public int getDcId() {
return dcId;
}
public void setDcId(int dcId) {
this.dcId = dcId;
}
public int getmId() {
return mId;
}
public void setmId(int mId) {
this.mId = mId;
}
public long getLastTime() {
return lastTime;
}
public void setLastTime(long lastTime) {
this.lastTime = lastTime;
}
public long getSeq() {
return seq;
}
public void setSeq(long seq) {
this.seq = seq;
}
public static void main(String[] args) {
SnowFlakeUtils sn = new SnowFlakeUtils(1, 1);
for (int i = 0; i < 2; i++) {
System.out.println(sn.getId());
System.out.println(sn.getId());
System.out.println(sn.getId());
}
}
}
猜你喜欢
- 2024-12-24 Java 8 新增6接口:Optional、Consumer等
- 2024-12-24 java小知识-纳秒 纳秒是什么
- 2024-12-24 弃用 Java 8,Apache Kafka 3.0 发布
- 2024-12-24 Sharding Sphere-JDBC从入门到实战,一顿饭的时间让你学懂
- 2024-12-24 Java虚拟机之 XX:+UseGCLogFileRotation 解析
- 2024-12-24 阿里Java三面:分布式延时任务方案解析,万字长文一篇点通你
- 2024-12-24 拯救Java应用:Arthas监控术,让你事半功倍
- 2024-12-24 java+uniapp实现微信JSSDK扫码功能
- 2024-12-24 filebeat收集K8S日志,写入自动创建的索引
- 2024-12-24 Java 动态调试技术原理及实践 java动态配置
你 发表评论:
欢迎- 04-27微服务部署架构设计详解(图文全面总结)
- 04-27Java微服务架构选型与对比:一场技术流派的巅峰对决
- 04-27微服务架构下Java的最佳实践
- 04-27Java微服务架构选型:优雅拆分与高效整合
- 04-27微服务架构下的Java代码拆分策略:像拼图一样构建系统
- 04-27微服务架构下的Java最佳实践
- 04-27微服务架构下Java的挑战与机遇
- 04-27微服务架构下Java事务管理的艺术
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)