开发全局唯一ID生成器

​ 保证id唯一的方法有很多种,本项目使用的是基于Redis的id生成器,其基本原理是借助于Redis自带的increment自增方法。

生成原理:以long类型作为生成id的类型,long类型具有64位,将这64位分为三部分,[63,63],[32,62],[0,31]。最高位是符号位,是一个固定值0,表示生成的id是非负数,后面63位需要决定生成id的唯一性。具体方法为,[0,31]位上填充由Redis的increment方法生成的值,[32,62]位填充当前时间距离某个基准时间的时间(一般以秒作为单位,69年后生成的值才会超过31位)。

实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.hmdp.utils;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;

/**
* 本类用于生成全局唯一ID
*/
@Component
public class UniqueIdGenerator {
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 2024.01.01 00:00:00作为基准时间
*/
private final long TIME_BEGIN = 1704067200L;

/**
* 根据不同的业务生成不同的id
* @param keyPrefix 业务
* @return
*/
public long generatorId(String keyPrefix){
long now = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);
long interval = now - TIME_BEGIN;

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy:MM:dd");
String timeStamp = simpleDateFormat.format(new Date());
//为了便于管理和查询,将当日时间融入key中
String key = keyPrefix + timeStamp;
Long count = stringRedisTemplate.opsForValue().increment(key);

Long id = interval << 32 | count;

return id;
}
}

学习完本节需要掌握以下知识点:

  1. 如何通过Redis生成全局唯一ID
  2. 时间戳的巧用