1. 无序型id
1. 优点
无序,无规律,不容易被遍历2. 缺点
无顺序,没有实际意义,不容易记忆3. 方案
1. UUID
2. 根据自己的规则生成例如数字+字母的唯一id
2. 自增型id
1. 优点
- InnoDB 使用两种索引来组织数据,Clustered Index 和 Second Index Clustered Index 与 主键有千丝万缕的关系,可以简单认为是相等关系,数据存储会按照主键来进行排序。如果在建表的时候不提供主键,InnoDB 会自动生成一个主键,这个主键是字符式的,所以当有新数据进来的时候,原先的排序会被打乱,中间的开销会很高。简单说就是那棵树的左旋右旋,很麻烦。使用自增 ID 充当主键,就可以解决这个问题了,相应的 Second Index 的查询效率也会变高。
- 而且自增型id可以根据id快捷的判断数据产生的先后顺序
2. 缺点
- 自增型id容易被人用程序遍历,如果拿到一个id,根据递增规律就可以遍历到所有数据,不安全
3. 实现方案
1. 数据库自增id
比如mysql的AUTO_INCREMENT
2. 根据自身的业务规则
比如年月日,时分秒,加上几位数字递增,这适合每天数据量小的场景。可以直接记录数据的日期
或者时间毫秒加上递增数字
3. 推特的分布式id生成方案
twitter在把存储系统从MySQL迁移到Cassandra的过程中由于Cassandra没有顺序ID生成机制,于是自己开发了一套全局唯一ID生成服务:Snowflake。
- 41位的时间序列(精确到毫秒,41位的长度可以使用69年)
- 10位的机器标识(10位的长度最多支持部署1024个节点)
- 12位的计数顺序号(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号) 最高位是符号位,始终为0。
public class IdWorker { private final long workerId; private final static long twepoch = 1288834974657L; private long sequence = 0L; private final static long workerIdBits = 4L; public final static long maxWorkerId = -1L ^ -1L << workerIdBits; private final static long sequenceBits = 10L; private final static long workerIdShift = sequenceBits; private final static long timestampLeftShift = sequenceBits + workerIdBits; public final static long sequenceMask = -1L ^ -1L << sequenceBits; private long lastTimestamp = -1L; public IdWorker(final long workerId) { super(); if (workerId > this.maxWorkerId || workerId < 0) { throw new IllegalArgumentException( String.format("worker Id can't be greater than %d or less than 0", this.maxWorkerId)); } this.workerId = workerId; } public synchronized long nextId() { long timestamp = this.timeGen(); if (this.lastTimestamp == timestamp) { this.sequence = (this.sequence + 1) & this.sequenceMask; if (this.sequence == 0) { System.out.println("###########" + sequenceMask); timestamp = this.tilNextMillis(this.lastTimestamp); } } else { this.sequence = 0; } if (timestamp < this.lastTimestamp) { try { throw new Exception(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", this.lastTimestamp - timestamp)); } catch (Exception e) { e.printStackTrace(); } } this.lastTimestamp = timestamp; long nextId = ((timestamp - twepoch << timestampLeftShift)) | (this.workerId << this.workerIdShift) | (this.sequence); System.out.println("timestamp:" + timestamp + ",timestampLeftShift:" + timestampLeftShift + ",nextId:" + nextId + ",workerId:" + workerId + ",sequence:" + sequence); return nextId; } private long tilNextMillis(final long lastTimestamp) { long timestamp = this.timeGen(); while (timestamp <= lastTimestamp) { timestamp = this.timeGen(); } return timestamp; } private long timeGen() { return System.currentTimeMillis(); } public static void main(String[] args) { IdWorker worker2 = new IdWorker(2); System.out.println(worker2.nextId()); } }