全局唯一的支付和订单id生成算法
数据库存储的是两个Long类型的复合主键。显示到页面的是一个27位的数字单号
package com.yunyihenkey.common.idworker; /**
*
* @desc
* @author jon snow
* @version 1.0.0
*/
public class SuperSnowflakeIdWorker { public static class NextId {
private Long id1;
private Long id2; public NextId(Long id1, Long id2) {
this.id1 = id1;
this.id2 = id2;
} public Long getId1() {
return id1;
} public void setId1(Long id1) {
this.id1 = id1;
} public Long getId2() {
return id2;
} public void setId2(Long id2) {
this.id2 = id2;
} } /** 开始时间截(秒) */
public static final long birth = 1498939440L; /** 机器id所占的位数 */
public static final long workerIdBits = 20L; /** 序列在id中占的位数 */
public static final long sequenceBits = 43L; /** 支持的最大机器id (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
public static final long maxWorkerId = -1L ^ (-1L << workerIdBits); /** 序列最大值 */
public static final long sequenceMask = -1L ^ (-1L << sequenceBits); /** 工作机器ID(0~1048575 ) */
private long workerId; /** 秒内序列(0~8796093022207) */
private long sequence = 0L; /** 上次生成ID的时间截 */
private long lastTimestamp = -1L; public SuperSnowflakeIdWorker(long workerId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(
String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
this.workerId = workerId;
} public synchronized NextId nextId() {
long timestamp = timeGen(); // 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format(
"Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
} // 如果是同一时间生成的,则进行秒内序列
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
// 秒内序列溢出
if (sequence == 0) {
// 阻塞到下一个秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp);
}
}
// 时间戳改变,秒内序列重置
else {
sequence = 0L;
} // 上次生成ID的时间截
lastTimestamp = timestamp; // 移位并通过或运算拼到一起组成64位的ID
// long l = (workerId << sequenceBits) | sequence; // System.out.println(Long.toBinaryString(workerId) + ":+:" +
// Long.toBinaryString(sequence));
// String binaryString = Long.toBinaryString(l);
// System.out.println("生成:" + zero.substring(0, 63 - binaryString.length()) +
// binaryString);
// System.out.println("生成数字:" + l + ":原始数字:"
// + Long.valueOf(Long.toBinaryString(workerId) + Long.toBinaryString(sequence),
// 2) + "end"); // return new long[] { timestamp - birth, (workerId << sequenceBits) | sequence
// };
return new NextId(timestamp - birth, (workerId << sequenceBits) | sequence);
} /**
* 阻塞到下一个秒,直到获得新的时间戳
*
* @param lastTimestamp
* 上次生成ID的时间截
* @return 当前时间戳
*/
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
} private long timeGen() {
return System.currentTimeMillis() / 1000;
} /** 测试生成id */
public static void main(String[] args) { SuperSnowflakeIdWorker idWorker = new SuperSnowflakeIdWorker(666);
long currentTimeMillis = System.currentTimeMillis();
int times = 100000000;
for (int i = 0; i < times; i++) { // 获取一个复合主键id
// NextId nextId = idWorker.nextId();
idWorker.nextId(); // System.out.println(Long.toBinaryString(id)); // System.out.println("--------------------------------");
// String zero =
// "000000000000000000000000000000000000000000000000000000000000000";// 63个0
// String binaryString = Long.toBinaryString(nextId.getId2());
// BigInteger bigInteger = new BigInteger(
// Long.toBinaryString(nextId.getId1()) + zero.substring(0, 63 -
// binaryString.length()) + binaryString,
// 2);
// String string = bigInteger.toString();
// System.out.println("数据库存储:id1=" + nextId.getId1() + "::id2=" +
// nextId.getId2() + "::::页面显示订单号:" + string);
// String string2 = bigInteger.toString(2);
// System.out.println("id的比特字节::" + string2);
//
// int endIndex = string2.length() - 63;
// System.out
// .println("前端传过来的订单号:" + string + "" + " 解析-->id1=" +
// Long.valueOf(string2.substring(0, endIndex), 2)
// + "::id2=" + Long.valueOf(string2.substring(endIndex), 2));
} long cost = System.currentTimeMillis() - currentTimeMillis;
long l = times / (cost == 0 ? 1 : cost) * 1000;
System.out.println("\r\n耗时(ms):" + cost + ",速度(万每秒):" + (l / 10000)); } // /** 测试是否重复 */
// public static final ConcurrentHashMap<Object, Object> map = new
// ConcurrentHashMap<>(1000100);
/** 测试是否重复 */
// public static void main666(String[] args) {
// // 9个线程
// for (int i = 0; i < 9; i++) {
// new Thread(new Runnable() {
// @Override
// public void run() {
// MySnow idWorker = new MySnow(Thread.currentThread().getId());
// for (int j = 0; j < 1000000; j++) {
// NextId nextId = idWorker.nextId();
// Object put = map.put(Long.toString(nextId.getId1()) +
// Long.toString(nextId.getId2()), 1);
// if (put != null) {
// System.out.println("id重复!!!");
// }
// }
// System.out.println(Thread.currentThread().getId() + ",线程跑完");
// }
// }).start();
//
// }
//
// } }
全局唯一的支付和订单id生成算法的更多相关文章
- 分布式系统的唯一id生成算法你了解吗?
在分库分表之后你必然要面对的一个问题,就是id咋生成? 因为要是一个表分成多个表之后,每个表的id都是从1开始累加自增长,那肯定不对啊. 举个例子,你的订单表拆分为了1024张订单表,每个表的id都从 ...
- 分布式全局不重复ID生成算法
分布式全局不重复ID生成算法 算法全局id唯一id 在分布式系统中经常会使用到生成全局唯一不重复ID的情况.本篇博客介绍生成的一些方法. 常见的一些方式: 1.通过DB做全局自增操作 优点:简单.高 ...
- 分布式唯一ID生成算法-雪花算法
在我们的工作中,数据库某些表的字段会用到唯一的,趋势递增的订单编号,我们将介绍两种方法,一种是传统的采用随机数生成的方式,另外一种是采用当前比较流行的“分布式唯一ID生成算法-雪花算法”来实现. 一. ...
- 唯一ID生成算法剖析
https://mp.weixin.qq.com/s/E3PGP6FDBFUcghYfpe6vsg 唯一ID生成算法剖析 原创 cloudoxou 腾讯技术工程 2019-10-08
- 美团技术分享:深度解密美团的分布式ID生成算法
本文来自美团技术团队“照东”的分享,原题<Leaf——美团点评分布式ID生成系统>,收录时有勘误.修订并重新排版,感谢原作者的分享. 1.引言 鉴于IM系统中聊天消息ID生成算法和生成策略 ...
- 分布式 ID 生成算法 — SnowFlake
一.概述 分布式 ID 生成算法的有很多种,Twitter 的 SnowFlake 就是其中经典的一种. SnowFlake 算法生成 ID 的结果是一个 64bit 大小的整数,它的结构如下图: 1 ...
- 理解分布式id生成算法SnowFlake
理解分布式id生成算法SnowFlake https://segmentfault.com/a/1190000011282426#articleHeader2 分布式id生成算法的有很多种,Twitt ...
- 开源一个比雪花算法更好用的ID生成算法(雪花漂移)
比雪花算法更好用的ID生成算法(单机或分布式唯一ID) 转载及版权声明 本人从未在博客园之外的网站,发表过本算法长文,其它网站所现文章,均属他人拷贝之作. 所有拷贝之作,均须保留项目开源链接,否则禁止 ...
- Twitter的SnowFlake分布式id生成算法
二进制相关知识回顾 1.所有的数据都是以二进制的形式存储在硬盘上.对于一个字节的8位到底是什么类型 计算机是如何分辨的呢? 其实计算机并不负责判断数据类型,数据类型是程序告诉计算机该如何解释内存块. ...
随机推荐
- AWK学习总结(三) Records and Fields
AWK 记录和域 The NR Variable % awk '{print NR, $0}' employees 1 Tom Jones 4424 5/12/66 543354 2 Mary Ada ...
- robot framework运行测试 命令行启动
...\rf_test> pybot --test test_case test_suit.robot #运行一条用例 ...\rf_test> pybot test_suit.robot ...
- Ubuntu 16.04 + github page + hexo 搭建博客
1. 安装nodejs: sudo apt-get install nodejs-legacy 2.安装nvm : wget -qO- https://raw.github.com/creatio ...
- MySQL 启动服务和登陆参数
启动MySQL服务:net start mysql; 停止MySQL服务:net stop mysql; 参数 描述 -D,--database=name 打开指定数据库 --delimiter=na ...
- E20170602-ts
questionnaire n. 调查问卷; 调查表; アンケート不是英语 collection n. 征收; 收集,采集; 收藏品; 募捐; association n. 联想; 协会, ...
- Geometry Shader 实现 Wireframe 绘制边线的Shader
最终效果: 参考了一个免费插件 https://assetstore.unity.com/packages/vfx/shaders/directx-11/ucla-wireframe-shader-2 ...
- 赋予option元素点击事件后,点击select时却触发了option事件。如何解决?
将select的优先级提到option之前就可以了. 方法:为select元素添加position:relative: <select class="adt" name=&q ...
- JS 实现PDF文件打印
function PdfPrint() { bdhtml = window.document.body.innerHTML; sprnstr = "<!-- ...
- 清理TIME_WAIT
cat >> /etc/sysctl.conf << EOFnet.ipv4.tcp_tw_reuse=1net.ipv4.tcp_tw_recycle=1net.ipv4.t ...
- Oracle取查询结果数据的第一条记录SQL
Oracle取查询结果数据的第一条记录SQL: ; ;