系列博客目錄
文章目錄
- 系列博客目錄
- Why
- Redis自增ID策略
Why
我們需要設置全局唯一ID。原因:當用戶搶購時,就會生成訂單并保存到tb_voucher_order這張表中,而訂單表如果使用數據庫自增ID就存在一些問題。
問題:id的規律性太明顯、受單表數據量的限制。所以在自己的項目中,針對上傳的數據的ID的生成也可以使用全局唯一ID。表中有ID,屬性類型(文本、音頻、圖像)以及存儲位置,文件名(文件名由ID+原始文件名作為后綴組成)。
多種ID比如用戶ID,訂單ID。
全局ID生成器,是一種在分布式系統下用來生成全局唯一ID的工具,一般要滿足下列特性:高可用、唯一性、高性能、遞增性、安全性。
Redis自增ID策略
為了增加ID的安全性,我們可以不直接使用Redis自增的數值,而是拼接一些其它信息:
ID的組成部分:
- 符號位:1bit,永遠為0
- 時間戳:31bit,以秒為單位,可以使用69年
- 序列號:32bit,秒內的計數器,支持每秒產生2^32個不同ID
package com.hmdp.utils;import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;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;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;}
}
使用的示例代碼如下:
// 7.創建訂單
VoucherOrder voucherOrder = new VoucherOrder();
// 7.1.訂單id
long orderId = redisIdWorker.nextId("order");
voucherOrder.setId(orderId);
// 7.2.用戶id
voucherOrder.setUserId(userId);
// 7.3.代金券id
voucherOrder.setVoucherId(voucherId);
save(voucherOrder);// 7.返回訂單id
return Result.ok(orderId);
每天一個key,方便統計訂單量
ID 的構造是 :時間戳 + 計數器