全局唯一ID

数据类型:String

问题:ID 唯一性,在分布式系统中,多个服务节点或者多个进程可能会同时生成 ID。如果使用传统的自增 ID 生成方式,可能会出现 ID 冲突的问题。通过结合时间戳和序列号,利用 Redis 的原子性操作生成全局唯一 ID,确保在分布式环境下生成的 ID 是唯一的。生成的 ID 具有趋势递增的特性,这对于数据库的索引优化非常有帮助。在数据库中,递增的 ID 可以减少索引的碎片,提高查询效率。

技术:借助 Redis 的原子性操作 INCR 来生成序列号,确保在分布式环境下序列号的唯一性和原子性。

应用场景:在电商系统中,订单、商品、用户等数据都需要唯一的标识。使用全局唯一 ID 可以确保不同业务模块之间的数据关联和查询不会出现冲突。例如,每个订单都有一个唯一的订单号,方便订单的跟踪和管理。

Redis命令:INCR icr:product:2025:04:04,INCR命令是 Redis 的原子性操作,它会将指定键的值加 1,如果键不存在,则会先将键的值初始化为 0 再进行加 1 操作。这个命令确保了在高并发场景下序列号的生成是线程安全的。

java实现

// 64位:1(符号位,永为0)、2-32(时间戳,以秒为单位)、33-64(序列号,秒内的计数器)
// 1.生成时间戳
LocalDateTime now = LocalDateTime.now();
long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
long timestamp = nowSecond - BEGIN_TIMESTAMP;
​
//生成序列号
long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);
​
// 3.拼接并返回
return timestamp << 32 | count;

对应具体业务示例:

@Component
public class RedisIdWorker {
    /**
     * 开始时间戳
     */
    private static final long BEGIN_TIMESTAMP = 1640995200L;
    /**
     * 序列号的位数
     */
    private static final int COUNT_BITS = 32;
​
    private StringRedisTemplate stringRedisTemplate;
​
    public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {
        this.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.获取当前日期,精确到天
        String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        // 2.2.自增长
        long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);
​
        // 3.拼接并返回
        return timestamp << COUNT_BITS | count;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值