数据中主键有多种方式:数据库自增、程序生成。程序生成一般采用的是snowflake 算法。这个算法在网上有很多解释,这里就不做过多的解释。
生成的id大致有以下组成:
Snowflake算法一般生成的每一个ID都是64位的整型数,它的核心算法也比较简单高效,结构如下:
41位的时间序列,精确到毫秒级,41位的长度可以使用69年。时间位还有一个很重要的作用是可以根据时间进行排序。
5位的数据中心标识,5位的长度最多支持部署32个节点。
8位的机器标识,8位的长度最多支持部署255个节点。
12位的计数序列号,序列号即一系列的自增id,可以支持同一节点同一毫秒生成多个ID序号,12位的计数序列号支持每个节点每毫秒产生4095个ID序号。
最高位是符号位,始终为0,不可用。
根据生成规则和实际代码:
(有关算法详解:https://segmentfault.com/a/1190000011282426#articleHeader2)
return ((timestamp - 1288834974657) << 25) |
(datacenterId << 20) |
(workerId << 12) |
sequence;
那么我们将生成的id (503565670412513280)转换为2进制:
11011111101000001100100111100101010000001001111000000000000
将其进行拆分
1101111110100001110010000011011001 00000 00010001 000000000000
然后在将各个位置的二进制编码转换为10进制就ok
实例代码:
public JSONObject parseInfo(String id) {
id = Long.toBinaryString(Long.parseLong(id));
int len = id.length();
JSONObject jsonObject = new JSONObject();
int sequenceStart = len < workerIdShift ? 0 : len - workerIdShift;
int workerStart = len < dataCenterIdShift ? 0 : len - dataCenterIdShift;
int timeStart = len < timestampLeftShift ? 0 : len - timestampLeftShift;
String sequence = id.substring(sequenceStart, len);
String workerId = sequenceStart == 0 ? "0" : id.substring(workerStart, sequenceStart);
String dataCenterId = workerStart == 0 ? "0" : id.substring(timeStart, workerStart);
String time = timeStart == 0 ? "0" : id.substring(0, timeStart);
int sequenceInt = Integer.valueOf(sequence, 2);
jsonObject.put("sequence", sequenceInt);
int workerIdInt = Integer.valueOf(workerId, 2);
jsonObject.put("workerId", workerIdInt);
int dataCenterIdInt = Integer.valueOf(dataCenterId, 2);
jsonObject.put("dataCenter", dataCenterIdInt);
long diffTime = Long.parseLong(time, 2);
long timeLong = diffTime + startTime;
String date = DateUtil.formatTime(null, timeLong);
jsonObject.put("date", date);
return jsonObject;
}