redis实现全局唯一id

Redis 中的INCREMENT操作。
简单来说,Redis 的 INCREMENT 操作指的是对一个存储在 Redis 中的整数值进行“增加”的命令。这些命令是原子性(Atomic) 的,这是它们最核心、最重要的特性。
在深入命令之前,必须先理解“原子性”。原子性意味着一个操作是不可分割的。即使有多个客户端同时连接到 Redis 服务器并对同一个键(Key)进行增减操作,Redis 也会确保这些命令一个接一
个地顺序执行,而不会出现竞争条件(Race Condition)。
例如,如果键 mycounter 的值是 10,同时有 1000 个客户端执行 INCR mycounter 命令,最终的结果一定是 1010,绝对不会出现丢失任何一次增加的情况。
这使得 Redis 的 INCREMENT 命令成为实现高并发计数器的完美选择。
具体实现:
RedisIdWorker
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 SEGIN_TIMESTAMP = 1735689600L;
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 - SEGIN_TIMESTAMP;
// 2.生成序列号,获取当前日期,自增长
String data = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + data);
// 3.拼接并返回
return timestamp << COUNT_BITS | count;
}
}
测试:
package com.hmdp;
import com.hmdp.entity.Shop;
import com.hmdp.service.impl.ShopServiceImpl;
import com.hmdp.utils.CacheClient;
import com.hmdp.utils.RedisIdWorker;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.concurrent.*;
import static com.hmdp.utils.RedisConstants.CACHE_SHOP_KEY;
@SpringBootTest
class HmDianPingApplicationTests {
@Resource
private CacheClient cacheClient;
@Resource
private ShopServiceImpl shopService;
@Resource
private RedisIdWorker redisIdWorker;
private ExecutorService es = Executors.newFixedThreadPool(500);
@Test
void testIdWorker() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(300);
Runnable task = () ->{
for(int i = 0;i < 100;i++){
long id = redisIdWorker.nextId("order");
System.out.println(id);
}
latch.countDown();
};
long start = System.currentTimeMillis();
for(int i = 0;i < 300;i++){
es.submit(task);
}
latch.await();
long end = System.currentTimeMillis();
System.out.println("time:" + (end - start));
}
@Test
void testSaveShop() throws InterruptedException {
Shop shop = shopService.getById(1L);
cacheClient.setWithLogicalExpire(CACHE_SHOP_KEY + 1L,shop,10L, TimeUnit.SECONDS);
}
}
浙公网安备 33010602011771号