生成全局唯一id

177 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 16 天,点击查看活动详情

前言

连续写了这多天的redis有关的东西,今天我来写写有关业务的一些要点。而今天这篇就是有关全局唯一id的。

全局唯一id的重要性

首先来说说为什么我们需要这个全局唯一id。有些人可能会说这“玩意怎么会重要呢,使用数据库的自增不就好了?”。其实这句话对也不对。数据库的自增确实符合全局唯一id的几个要求(全局唯一性,单调递增)。但是有时出于需求我们不得不进行分库分表时,数据库自增就没有办法保持全局一致性了。同时在一些订单业务时,如果我们也使用数据库自增的话,就非常容易被别有用心之人知道我们对应的信息,这时我们就需要别的办法生成全局唯一id了。所以接下来介绍几种生成方法(重点介绍UUID)

UUID

UUID(Universally Unique Identifier)即唯一通用识别码。这是由我们自己定义的唯一id生成器。由我们自己在程序中生成,说明其api调用非常方便,也有别人直接写好了的api引入对应的库即可。像java就有着对应的api。

`UUID uuid = UUID.randomUUID();

但是我们也可以自己写一个,以下为对应代码。

public long nextId(String prefixKey)
{
    //先定义一个最初的时间,就是定义的变量
    //然后获取当前的时间戳
    long seconds = Instant.now().getEpochSecond();
    //两者相减
    long timeStamp = seconds-BEGIN_BITS;
    //先生成key,用时间也是为了方便统计
    String format = LocalDateTime.now().format(
            DateTimeFormatter.ofPattern("yyyy-MM-dd")
    );

    String key = prefixKey+":"+format;
    //从redis中拿到自增序列号
    Long increment = stringRedisTemplate.opsForValue().increment(key);
    //这里先向左平移32位,然后异或序列号(因为后面都是0)
    return timeStamp<<32|increment;

首先来说说我实现的思路就是用时间戳然后向左移动32位,最后再异或一个自增,除非两个部分都一样(时间戳和自增的结果),不然一定不是重复的。

缺点

为了保证不重复,我们往往需要比较长的数字,这就造成其传输数据量比较大,不适合做主键,同时其代表的意思往往比较抽象。