在接触UUID之前,我建表用的ID一直是用的int型,然后自动增长,这样很方便。
但是这样做却有一些问题,因为数据量大的话,不可能只用一张表,而是几张表,这样会出现id重复,于是有了UUID。
UUID 是 通用唯一识别码(Universally Unique Identifier)的缩写,是一种软件建构的标准。其目的,是让分布式系统中的所有元素,都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此一来,每个人都可以创建不与其它人冲突的UUID。在这样的情况下,就不需考虑数据库创建时的名称重复问题。
接下来便说一下用JAVA生成UUID并应用到数据库中的例子。
public static String getUUID() {String id =null;UUID uuid = UUID.randomUUID();id = uuid.toString();//去掉随机ID的短横线id = id.replace("-", "");//将随机ID换成数字int num = id.hashCode();//去绝对值num = num < 0 ? -num : num;id = String.valueOf(num);return id;}
jdk早已支持UUID,并可以直接使用,只需import java.util.UUID
,即可直接调用UUID的静态方法randomUUID(),生成一个唯一的UUID。
但是这个UUID其实是用的16进制,而且包含了非数字字符:“-”,比如:
e3f6eec7-d9f4-4b78-b242-749851a2d922
一般我们是要去掉短横线,当然不去掉也是可以的。
去掉“-”字符,首先将UUID转化为String,然后用replace("-", “”)方法,将UUID中的“-”替换为空字符,这样就可以将UUID的短横线去掉了。
e3f6eec7d9f44b78b242749851a2d922
到这里,UUID其实也算是一串数字,可以作为ID了。
但是作为id的话,可能有些不太好看,所以我们可以将它再转换一下,变成纯数字。
比如我们可以获得目前这个字符串的哈希码,一个字符串,自然是对应一个哈希码。(可能存在哈希冲突)
int num = id.hashCode();s
hashCode()返回的是一个Int型数字,且有正负。
一般要将负号去掉:
num = num < 0 ? -num : num;
最后一般将这个数字转化为String类型,当然就用int也是可以的
长度:(10位,或9位)
2.0
以上的主键id生成策略仅仅只是初级,下面对比目前几种常用的 id生成策略 的优劣。
1. Sequence ID
数据库自增长序列或字段,最常见的方式。由数据库维护,数据库 单表唯一。
优点:
- 简单,代码方便。
- 性能高。
- 占用内存小。
- 数字ID天然排序,对分页或者需要排序的结果很有帮助。
缺点:
- 不同数据库语法和实现不同,数据库迁移、多数据库版本支持的时候需要处理。
- 数据库合并、迁移时非常痛苦。
- 分表分库的时候会有麻烦。
优化方案:
针对每个表,自定义不同的自增规则:
比如:book1 生成的是 1,4,7,10,book2生成的是2,5,8,11,book3生成的是 3,6,9,12。这样就可以有效生成集群中的唯一ID,也可以大大降低ID生成数据库操作的负载。
(但是不能有效解决新旧表合并id冲突问题)
总结:当数据量很大时,将会有致命缺陷。
2. UUID
常见的方式。
UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。
优点:
- 简单,代码方便。
- 全球唯一,在遇见数据迁移,系统数据合并,或者数据库变更等情况下,可以从容应对。
缺点:
- 没有排序,无法保证趋势递增。
- UUID往往是使用字符串存储,查询的效率比较低。
- 存储空间比较大,如果是海量数据库,就需要考虑存储量的问题。
- 传输数据量大
- 不可读。
优化方案:
- 解决UUID不可读:使用UUID to Int64的方法。
- 解决UUID字符串、太长:使用UUID 的 hashcode。
- 解决UUID无序、不可读:使用UUID 的 hashcode ,并在其前加入时间戳
3. GUID
GUID:是微软对UUID这个标准的实现。UUID还有其它各种实现,不止GUID一种。优缺点同UUID。
4.时间戳
利用时间的增长性,可以作为id。
在java中,使用System.currentTimeMillis()
可以获取系统时间,毫秒级,目前的位数为13位,long型。
优点:
- 简单,代码方便。
- 长度适中,存储空间适中。
- 数值型,查询效率高。
- 有序,递增
缺点:
- 重复率较大,java程序每毫秒可产生几十个相同的时间戳。
- 基本不可读
优化方案:
1.解决重复: 在时间戳后,加上UUID的hashcode
2.解决不可读:将时间戳转换格式:yyyyMMddhhmmssSSS
5. COMB
COMB(combine)型是数据库特有的一种设计思想,可以理解为一种改进的GUID,它通过组合GUID和系统时间,以使其在索引和检索事有更优的性能。
数据库中没有COMB类型,它是Jimmy Nilsson在他的“The Cost of GUIDs as Primary Keys”一文中设计出来的。
COMB数据类型的基本设计思路是这样的:既然UniqueIdentifier数据因毫无规律可言造成索引效率低下,影响了系统的性能,那么我们能不能通过组合的方式,保留UniqueIdentifier的前10个字节,用后6个字节表示GUID生成的时间(DateTime),这样我们将时间信息与UniqueIdentifier组合起来,在保留UniqueIdentifier的唯一性的同时增加了有序性,以此来提高索引效率。
优点:
- 有序
- 性能优于UUID。
6. Twitter的snowflake算法
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。snowflake算法可以根据自身项目的需要进行一定的修改。比如估算未来的数据中心个数,每个数据中心的机器数以及统一毫秒可以能的并发数来调整在算法中所需要的bit数。
优点:
不依赖于数据库,灵活方便,且性能优于数据库。
ID按照时间在单机上是递增的。
缺点:
在单机上是递增的,但是由于涉及到分布式环境,每台机器上的时钟不可能完全同步,也许有时候也会出现不是全局递增的情况。
在这里推荐一个id生成工具:hutool
hutool 是一个中国人开发的java工具包,里面有很多实用的、封装完善的类,包括id、字符串、二维码等可以说是很全了。
小伙伴们有兴趣的可以了解下。