Redis实战(使用Scan,Lua脚本,一次扣多个库存,多线程并发使用,并发获取分布式锁,BItMap实现签到和在线统计)

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);
    }

}
相关推荐
风象南30 分钟前
Spring Boot 实现文件秒传功能
java·spring boot·后端
橘猫云计算机设计31 分钟前
基于django优秀少儿图书推荐网(源码+lw+部署文档+讲解),源码可白嫖!
java·spring boot·后端·python·小程序·django·毕业设计
黑猫Teng35 分钟前
Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实战指南
java·spring boot·后端
星河浪人41 分钟前
Spring Boot启动流程及源码实现深度解析
java·spring boot·后端
佩奇的技术笔记42 分钟前
中级:Maven面试题精讲
java·面试·maven
Lizhihao_1 小时前
JAVA-堆 和 堆排序
java·开发语言
极客先躯1 小时前
高级java每日一道面试题-2025年3月21日-微服务篇[Nacos篇]-什么是Nacos?
java·开发语言·微服务
工业互联网专业1 小时前
基于springboot+vue的动漫交流与推荐平台
java·vue.js·spring boot·毕业设计·源码·课程设计·动漫交流与推荐平台
雷渊1 小时前
深入分析Spring的事务隔离级别及实现原理
java·后端·面试
rebel1 小时前
Java获取excel附件并解析解决方案
java·后端