1.使用Scan
2.lua脚本操作Redis
一次扣减一个商品库存
一次扣减多个商品的库存
java
复制代码
@Test
void test100() {
String key = "product.1";
stringRedisTemplate.opsForValue().set("product.1","10");
stringRedisTemplate.opsForValue().set("product.2","20");
stringRedisTemplate.opsForValue().set("product.3","30");
}
@Test //模拟下单扣多个商品库存
void test3() {
ArrayList<FreezeProduct> freezeProducts = CollUtil.newArrayList(
new FreezeProduct().setProductId(1).setQty(5),
new FreezeProduct().setProductId(2).setQty(5),
new FreezeProduct().setProductId(3).setQty(5)
);
StringBuilder sb = new StringBuilder();
// 1. 我要知道需求量是多少 ,还要知道是哪个key
sb.append(" local myTable = {} ");
// 2. 我要判断目前的库存量是否满足需求量
sb.append(" local redisQtys = redis.call('mget',unpack(KEYS)) ");
sb.append(" for i = 1, #KEYS do ");
sb.append(" if tonumber(ARGV[i]) > tonumber(redisQtys[i]) then ");
sb.append(" myTable[#myTable + 1] = KEYS[i] .. '=' .. redisQtys[i] ");
sb.append(" end ");
sb.append(" end ");
// 3. myTable 有元素 return ,没有元素 就扣
sb.append(" if #myTable > 0 then ");
sb.append(" return myTable ");
sb.append(" end ");
sb.append(" for i = 1 , #KEYS do");
sb.append(" redis.call('decrby',KEYS[i],ARGV[i]) ");
sb.append(" end ");
sb.append(" return {} ");
// 返回 : 如果不足 集合 ,如果 满足:空集合
RedisScript<List> script = RedisScript.of(sb.toString(),List.class);
List<String> keys = freezeProducts.stream().map(it -> "product." + it.getProductId()).collect(Collectors.toList());
Object[] qtys = freezeProducts.stream().map(it -> it.getQty() + "").toArray();
List list = stringRedisTemplate.execute(script, keys,qtys);
if(list.isEmpty()){
System.out.println(StrUtil.format("下单成功"));
} else {
System.out.println(StrUtil.format("下单失败,{}",list));
}
}
3.模拟多线程并发使用Decrby
java
复制代码
public class DecrByDemo {
@Resource(name = "redisTemplate")
private ValueOperations<String, Integer> valueOperations;
private static final String key = "product.01";
public void test() {
valueOperations.set(key, 5);
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
executorService.execute(() -> {
Integer value = valueOperations.get(key);
if (value >= 1) {
valueOperations.set(key, value - 1);
System.out.println(StrUtil.format("线程{} -> 扣减成功", Thread.currentThread().getName()));
} else {
System.out.println(StrUtil.format("线程{} -> 扣减失败", Thread.currentThread().getName()));
}
});
}
System.in.read();
}
public void test2() {
valueOperations.set(key, 5);
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
executorService.execute(() -> {
Long value = valueOperations.decrement(key);
if (value >= 0) {
System.out.println(StrUtil.format("线程{} -> 扣减成功,剩余库存{}", Thread.currentThread().getName(),value));
} else {
System.out.println(StrUtil.format("线程{} -> 扣减失败", Thread.currentThread().getName()));
}
});
}
System.in.read();
}
}
4.模拟多线程并发获取分布式锁SetNX
java
复制代码
@Component
public class SetNxDemo {
@Resource(name = "redisTemplate")
private ValueOperations<String, String> valueOperations;
public void test() throws InterruptedException {
//出入库场景
ExecutorService executorService = Executors.newCachedThreadPool();
for(int i =1; i<6;i++){
executorService.execute(()->{
while (true){
// 获取分布式锁
Boolean b = valueOperations.setIfAbsent("wms.io.locker", DateUtil.now());
if(b){
System.out.println(Thread.currentThread().getName() + " 获取到了分布式锁" );
ThreadUtil.safeSleep(5000); //模拟业务操作
stringRedisTemplate.delete("wms.io.locker");
break;
} else {
System.out.println(Thread.currentThread().getName() + " 获取锁失败,睡眠2s" );
ThreadUtil.safeSleep(2000);
}
}
});
}
System.in.read();
}
}
5.BitMap
签到
java
复制代码
@Component
public class BitMapDemo {
@Autowired
private StringRedisTemplate stringRedisTemplate;
private final String key ="sign.2024.zhouxingxing";
public void test(){
//设置签到
stringRedisTemplate.opsForValue().setBit(key,2,true);
stringRedisTemplate.opsForValue().setBit(key,85,true);
//获取周星星同学的签到天数
RedisCallback<Long> callback = connection -> { return connection.bitCount(key.getBytes(),0,365);};
Long count = stringRedisTemplate.execute(callback);
//打印周星星2024年签到天数
System.out.println("周星星2024年一共签到天数:"+count);
}
}
模拟在线统计
java
复制代码
@Component
public class BitMapDemo {
@Resource(name = "redisTemplate")
private ValueOperations valueOperations;
@Autowired
private StringRedisTemplate redisTemplate;
private static final int user01 = 1;
private static final int user02 = 2;
private static final int user03 = 3;
private static String key20220601 = "20200601";
private static String key20220602 = "20200602";
private static String key20220603 = "20200603";
private static String saveKey = "q1";
public void test() {
valueOperations.setBit(key20220601, user01, true);
valueOperations.setBit(key20220601, user02, true);
valueOperations.setBit(key20220602, user02, true);
valueOperations.setBit(key20220603, user01, true);
valueOperations.setBit(key20220603, user03, true);
//1. 一直在线人数统计
//2. 时间段活跃用户
RedisCallback<Long> callback = connection -> {
return connection.bitOp(RedisStringCommands.BitOperation.AND, saveKey.getBytes(),
key20220601.getBytes(), key20220602.getBytes(), key20220603.getBytes());
};
Long value = redisTemplate.execute(callback);
RedisCallback<Long> callback2 = connection -> {
return connection.bitCount(saveKey.getBytes());
};
Long value2 = redisTemplate.execute(callback2);
System.out.println(value2);
}
}