1 概述
在实际项目中,根据不同的业务逻辑需要生成唯一的标识id ,如购买商品生成的订单号。尽管这个标识id功能非常的简单,但是如果不能成功的生成唯一标识id,那将会影响后续的业务逻辑 。我们可以使用数据库去生成唯一标识id,但是其性能受到数据库性能的硬性,且随机标识id过于简单会暴露业务信息。
所以意味着,生成唯一标识的逻辑方法需要高性能且高可用。并且需要高安全性,不能暴露出业务信息。在这篇文章中,将使用redis数据库区生成唯一的标识id
生成的逻辑是时间戳 + r e d i s 自增序列号 \textcolor{red}{生成的逻辑是 时间戳+redis 自增序列号} 生成的逻辑是时间戳+redis自增序列号
序列号的类型可以为Long 类型,数据值足够大,可以确保ID唯一不重复
逻辑: 通过时间戳左移31位,并与低32位的序列号值或
2 方法实现
K e y 分析 \textcolor{blue}{Key 分析} Key分析
(1)Key 前缀为 lock:
(2)该唯一标识id 的生成器 应该与不同的业务逻辑区分。 所以应该拼接服务的名称信息。如订单的唯一标识id key的结构可以为lock:order:
V a l u e 分析 \textcolor{blue}{Value 分析} Value分析
String 结构去存储自增值,每次自增一即可。
/*** @Description redis 唯一id生成器**/
@Component
public class RedisIdWorker {private final static long BEGIN_TIMESTAMP=1672531200L;private final static int BITS_COUNT=32;private final static String LOCK_PREFIX="lock:";private StringRedisTemplate redisTemplate;public RedisIdWorker(StringRedisTemplate redisTemplate){this.redisTemplate=redisTemplate;}/*** 根据业务场景生成唯一标识id* 生成逻辑是32位时间戳+自增值构成的64位数* @param prefix* @return*/public long uniqId(String serviceName){//生成时间戳Long now = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);Long l1 = now - BEGIN_TIMESTAMP;//从Redis中获得自增序列号String key=prefix+serviceName;Long increment = redisTemplate.opsForValue().increment(key);//拼接返回数据 高位向左移32位 与 32位低位与//序列号为64位的long值return l1<<BITS_COUNT|increment;}
}