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());
}
}
本文探讨了无序型和自增型ID的特点与应用场景,并详细介绍了包括UUID、自增ID及Twitter的Snowflake算法在内的多种ID生成方案。着重分析了自增ID在数据库性能优化方面的优势及其潜在的安全风险。
278

被折叠的 条评论
为什么被折叠?



