专门搞一张表用来生成主键,甚至可以单独部署一个MySQL实例用来做这个事情。所有需要主键的地方都统一从这张表获取。优点是简单,缺点就是并发不高,并且会出现单点故障。
属于“数据库自增ID”方案的升级版,利用多个MySQL实例来生成ID,即提高了并发,又解决了单点故障的问题。具体使用哪个MySQL实例,可以采用随机或轮询的方式。既然多个数据库同时在生成ID,那么如何保证生成的ID不重复呢?答案是采用不同初始值+固定步长的方式,比如现在有两个数据库,A库的初始值是1,B库的初始值是2,步长是2,那么A库生成的ID序列是1、3、5、7…,B库生成的主键序列是2、4、6、8…,非常容易看出它们都错开了。
这种方案实现简单,性能也达标、还能解决单点问题。缺点是不易拓展,假如有一天要再增加一个数据库来进一步提高并发,就不好搞了。
每次从数据库获取一批ID并记录在内存里,而不是一个ID。比如初始ID是1,每次获取1000个,在获取ID的时候将ID改为1001,并返回1(查询和修改需要保证线程安全,可利用数据库悲观锁来实现),[1,1000]就是获取到的这一批ID了,下次再获取的话就是[1001, 2000]这一号段了。
这种方式可以减少查询数据库的次数,性能上有所提升,缺点是重启服务的话会丢失一段ID,导致ID空洞。
本地生成,不需要借助数据库,非常方便。但是缺点也很明显,一是太长,需要更多的存储空间;二是不连续,用作数据库主键的话会严重影响数据库写入效率。因为聚集索引的数据结构是B+树,如果是连续的主键,只需要顺序的append就行,不连续的主键每次写入B+树都要进行调整,非常影响性能。
ID是整型long,long占64个比特位,从左往右,第一个比特位是符号位,固定为0(ID都是正数),雪花算法规定后续41个比特位代表时间,单位为毫秒,为了让ID从更小的值开始,可以使用时间的差值,比如用当前时间减去服务上线前的某一个时间。接着后续10个比特位记录工作机器ID(5个比特位是机房ID,5个比特位是机器ID),最后12个比特位是同一个机器同一个时间产生的不同ID。