📝个人主页:五敷有你
🔥系列专栏:SpringBoot
⛺️稳中求进,晒太阳
每个店铺都可以发布优惠卷
当用户抢购时,就会生成订单并保存到tb_voucher_order这张表中,而订单表如果使用数据库自增id就存在一些问题:
1.id的规律性太明显
2.受单表数据量的限制
全局ID生成器是一种在分布式系统下用来生成全局唯一ID的工具,一般要满足下列特性:
- 高可用
- 唯一性
- 高性能
- 递增
- 安全性
为了增加ID的安全性,我们可以不直接使用Redis自增的数值,而是拼接一些其他信息:
ID组成部分:
符号位:1bit
时间戳:31bit,以秒为单位,可以用69年
序列号:秒内的计数器,支持每秒生成2^32个不同ID
关键代码:
package com.hmdp.utils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
@Component
public class RedisIdWorker {
private static final long BEGIN_TIMESTAMP=1640995200L;
private static final int COUNT_BITS=32;
StringRedisTemplate stringRedisTemplate;
public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
/**
* 这是一个全局ID
* @param keyPrefix
* @return
*/
public long nextId(String keyPrefix){
//1.生成时间戳
LocalDateTime now=LocalDateTime.now();
Long nowSecond=now.toEpochSecond(ZoneOffset.UTC);
long timestamp=nowSecond-BEGIN_TIMESTAMP;
//2.生成序列号
//获取当天日期,精确到天
String date=now.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
//自增长
long count=stringRedisTemplate.opsForValue().increment("icr:"+keyPrefix+":"+date);
//3.拼接并返回
/**
* 或运算 有1为1 无1为0
*/
return timestamp<<COUNT_BITS | count;
}
}