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 {@Resourceprivate CacheClient cacheClient;@Resourceprivate ShopServiceImpl shopService;@Resourceprivate RedisIdWorker redisIdWorker;private ExecutorService es = Executors.newFixedThreadPool(500);@Testvoid 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));}@Testvoid testSaveShop() throws InterruptedException {Shop shop = shopService.getById(1L);cacheClient.setWithLogicalExpire(CACHE_SHOP_KEY + 1L,shop,10L, TimeUnit.SECONDS);}
}