这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
前面学习了redis的一些基础操作和日常项目开发时使用缓存需要注意的几个问题,本节开始就是redis的一些实战代码。本节记录的是基于redis的全局唯一id生成器。
全局唯一ID
有些数据,例如账户等,与其他做外键连接需要一个全局唯一的标识,以防止数据冲突造成不可逆的破坏。一般来说,id有如下生成策略:
- UUID
- Redis自增
- snowflake算法
- 数据库自增
使用mysql开发时,全局唯一id一般使用雪花算法生成的id,这样生成的id可以保证在一个系统下唯一。然而在分布式系统下,这样生成的id可能也会出现重复的可能。因此,想要在分布式系统下实现全局唯一id,就需要另找他策。在进行redis的学习中,我学习到了基于redis的全局ID生成器,可在分布式系统下用来生成全局唯一ID的工具,同时具有唯一性,高可用,高性能,递增性,安全性的特点,可以较好地满足需求。
主要原理就是利用redis的步长自增,相当于分布式系统中用一个自增,redis的高性能可以满足这样生成id所需要的效率,同时配合时间戳就可生成一个分布式系统下的全局唯一id。
@Component
public class RedisIdWorker {
//开始时间戳
private static final long BEGIN_TIMESTAMP = 1640995200L;
//序列号位数
private static final long COUNT_BITS = 32;
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
*
* @param keyPrefix 业务前缀
* @return 全局唯一id
*/
public long nextId(String keyPrefix){
//1.生成时间戳
LocalDateTime now = LocalDateTime.now();
long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
long timestamp = nowSecond - BEGIN_TIMESTAMP;
//2.生成序列号
//2.1获取当前日期,精确到天
String day = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
//2.2自增长
long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + day);
//3.拼接并返回
return timestamp << COUNT_BITS | count;
}
}