UUID是否适合做订单ID问题

目录

UUID定义(直接查的)

UUID设计目的

UUID的组成

UUID的版本

      version1: 基于时间的

      version2: 基于DCE的

      version3: 基于MD5的

      version4: 基于伪随机数的

      version5: 基于SHA1的

UUID的样例

UUID是否可以做订单ID?

UUID为什么不建议做订单ID?      

首先-很难区分先后时间:

其次-表空间占用更大:

最后-对于mysql的B+Tree效率更低:

那么什么方法更适合生存订单ID呢?


UUID定义

      UUID是国际标准化组织(ISO)提出的一个概念。UUID是一个128比特的数值,这个数值可以通过一定的算法计算出来。为了提高效率,常用的UUID可缩短至16位。UUID用来识别属性类型,在所有空间和时间上被视为唯一的标识。一般来说,可以保证这个值是真正唯一的任何地方产生的任意一个UUID都不会有相同的值。使用UUID的一个好处是可以为新的服务创建新的标识符。这样一来,客户端在查找一个服务时,只需要在它的服务查找请求中指出与某类服务(或某个特定服务)有关的UUID,如果服务的提供者能将可用的服务与这个UUID相匹配,就返回一个响应。

UUID设计目的

       UUID的设计目的简单来说,就是让分布式系统中的所有元素,都能有一个唯一ID。UUID我们一般做开发的都会用到。生成一个UUID也很简单。

UUID的组成

      三部分组成。

      当前日期和时间,UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同。
      时钟序列。
      全局唯一的IEEE机器识别号,如果有网卡,从网卡MAC地址获得,没有网卡以其他方式获得      

      时间戳(当前日期+时间)+ 时钟序列 + 机器识别号(MAC、其他)

UUID的版本

      uuid有五个版本。分别是:

      version1: 基于时间的

          基于时间的UUID通过计算当前时间戳、随机数和机器MAC地址得到。由于在算法中使用了MAC地址,这个版本的UUID可以保证在全球范围的唯一性。但与此同时,使用MAC地址会带来安全性问题,这就是这个版本UUID受到批评的地方。如果应用只是在局域网中使用,也可以使用退化的算法,以IP地址来代替MAC地址--Java的UUID往往是这样实现的(当然也考虑了获取MAC的难度)。

      version2: 基于DCE的

          DCE(Distributed Computing Environment)安全的UUID和基于时间的UUID算法相同,但会把时间戳的前4位置换为POSIX的UID或GID。这个版本的UUID在实际中较少用到

      version3: 基于MD5的

          基于名字的UUID通过计算名字和名字空间的MD5散列值得到。这个版本的UUID保证了:相同名字空间中不同名字生成的UUID的唯一性;不同名字空间中的UUID的唯一性;相同名字空间中相同名字的UUID重复生成是相同的

      version4: 基于伪随机数的

          根据随机数,或者伪随机数生成UUID。这种UUID产生重复的概率是可以计算出来的,但随机的东西就像是买彩票:你指望它发财是不可能的

      version5: 基于SHA1的

          和基于名字的UUID算法类似,只是散列值计算使用SHA1(Secure Hash Algorithm 1)算法

 

UUID的样例

@Test
    public void uuid(){
        String uuid = UUID.randomUUID().toString();
        System.out.println(uuid);
    }

3b50fd3e-387e-49e6-844a-2dc407ed2223

be1540de-1265-423a-b5e4-c140da294899

查看源码:

public static UUID randomUUID() {
        SecureRandom ng = Holder.numberGenerator;

        byte[] randomBytes = new byte[16];
        ng.nextBytes(randomBytes);
        randomBytes[6]  &= 0x0f;  /* clear version        */
        randomBytes[6]  |= 0x40;  /* set to version 4     */
        randomBytes[8]  &= 0x3f;  /* clear variant        */
        randomBytes[8]  |= 0x80;  /* set to IETF variant  */
        return new UUID(randomBytes);
    }

  我们可以发现,java.util自带的uuid是采用的版本4。也就基于伪随机数的算法版本。

UUID是否可以做订单ID?

      uuid在不考虑时钟回拨问题的基础上,其实是可以做订单ID的,但是绝对不能使用java.util的基于伪随机数的方式。而是建议采用版本1,基于时间的。任何基于随机数的方法都不能确保不重复问题

UUID为什么不建议做订单ID?      

但是我们为什么一般不希望采用UUID做订单呢?

首先-很难区分先后时间:

      uuid很难通过肉眼判断订单的先后关系,必须去看创建时间。

其次-表空间占用更大:

      数据库类型中,我们看一下下表,数据库的类型大小

MySql常用数据类型
字段类型大小
tinyint1字节
int4字节
bigint8字节
char0-255字节
varchar0-65535字节

            如果使用uuid的方式,一般UUID生成以后都是一个36长度字串组成,我们必须采用varchar类型存储,非常占用空间

最后-对于mysql的B+Tree效率更低:

      数据入库操作:因为数据库都有事务性要求,存储引擎是InnoDB。该引擎存储数据的时候采用的是B+Tree存储。B+Tree的数据区是天然有序的。UUID的数据大小不可控的,根据B+Tree的要求,为了保持数据有序,数据等于插入操作。而如果订单ID是有序的,数据只需要追加操作就好了。

      数据库查询操作:  mysql查询数据库的时候,是需要先将数据从磁盘加载到内存中。这是一个标准的I/O动作。InnoDb每次加载数据的基本单位是16KB。如果UUID占了36byte,而int是4byte。那么每次加载数据分别是:16KB/36byte和16KB/4byte。可以看到,UUID因为占用空间更大,IO的读取次数肯定会相应增加

 

那么什么方法更适合生存订单ID呢?

雪花算法、美团的leaf算法等

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值