
import org.springframework.data.redis.core.StringRedisTemplate;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
/**
* @Projectname: hm-dianping
* @Filename: RedisIdWork
* @Author: SpringForest
* @Data:2022/12/23 11:09
* @Description:
* 1. 生成的ID总长度为32(如需修改长度请修改COUNT_BITS)
* 2. 最高位为符号位永远为0
* 3. 第1-32位为时间戳,最长使用时间为基准时间(可变)后69年
* 4. 第33-63位为序列号位,使用Redis生成,每秒最大可用ID为2^32个
*/
public class RedisIdWork {
/*
* 开始时间戳
* */
private static final long BEGIN_TIMESTAMP = 1640995200L;
/*
* 序列号的位数
* */
private static final int COUNT_BITS = 32;
@Resource
private StringRedisTemplate stringRedisTemplate;
public long nextId(String keyPrefix) {
// 1. 生成时间戳
LocalDateTime now = LocalDateTime.now();
long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
long timestamp = nowSecond - BEGIN_TIMESTAMP;
// 2. 生成序列号
// 2.1 获取精确到天作为前缀的一部分,防止某一天到达上线
now.format(DateTimeFormatter.ofPattern("yy yyMMdd"));
// 2.2 自增长
long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":");
// 3. 拼接并返回
// 3.1 使用位运算,将时间戳左移32位
// 3.2 使用或运算填充低位
return timestamp << COUNT_BITS | count;
}
/*
* 设置基准时间戳
* */
public static void main(String[] args) {
LocalDateTime time = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
long second = time.toEpochSecond(ZoneOffset.UTC);
System.out.println("s=" + second);
}
}