ID生成方案

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_INCREMENTjava

2. 根据自身的业务规则

好比年月日,时分秒,加上几位数字递增,这适合天天数据量小的场景。能够直接记录数据的日期mysql

或者时间毫秒加上递增数字sql


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());
	}

}