• Redisson-MultiLock使用


    环境说明
    由于测试条件有限以下测试都是使用的单机redis,官方推荐使用红锁是需要5台master。

    背景说明:
    最近的电商项目C端用户在购买商品时可以使用多种货币(余额、券、卡、积分)支付,同时B端商户也可以多这些货币进行管理(如 余额撤回、卡券作废、充值卡作废等),为了保证金额的安全问题,那么首选考虑的就是加锁,但是由于是多种货币可以同时使用且要保证则加锁得多维度批量加锁、支持分布式(B端和C端是在不同服务中)、保证批量加锁的原子性。
    基于以上分析和考虑,则选用了Redisson的multiLock。

    代码实现(springboot+redis):
    pom依赖

            
            
                org.redisson
                redisson-spring-boot-starter
                3.16.4
            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    RedissonConfig(配置类):

    @Configuration
    public class RedissonConfig {
    
        /**
         * 单Redis节点模式配置方法
         * 其他配置參數,看:
         *
         * @return
         */
        @Bean
        public RedissonClient redisson() {
            Config config = new Config();
            //单机模式  依次设置redis地址和密码
            config.useSingleServer().setAddress("redis://192.168.40.130:6379").setPassword("123456");
            return Redisson.create(config);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    MultiLockService(加锁类):

    @Component
    public class MultiLockService {
    
        @Autowired
        private RedissonClient redissonClient;
    
        public RLock tryMultiLock(List list){
            List locks = new ArrayList<>();
            list.forEach(key ->{
                RLock rLock = redissonClient.getLock(key);
                locks.add(rLock);
            });
            RLock[] array = locks.stream().toArray(RLock[]::new);
            RLock multiLock = redissonClient.getMultiLock(array);
            boolean isLook = multiLock.tryLock();
            if(isLook){
                return multiLock;
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    TestService(业务测试类)

    @Component
    @Slf4j
    public class TestService {
        @Autowired
        private MultiLockService lockService;
    
        @Async
        public void multiLock(){
            log.info("multiLock 尝试加锁...lock1、lock2、lock3");
            List list = new ArrayList<>();
            list.add("lock1");
            list.add("lock2");
            list.add("lock3");
            //加锁
            RLock multiLock = lockService.tryMultiLock(list);
            if(Objects.nonNull(multiLock)){
                log.info("multiLock 加锁成功,多锁为:lock1、lock2、lock3");
                try {
                    Thread.sleep(5000);
                }catch (Exception e){
                    log.error("休眠异常",e);
                } finally {
                    log.info("multiLock 开始解锁...");
                    multiLock.unlock();
                }
            } else {
                log.info("multiLock 尝试加锁失败...");
            }
        }
    
        @Async
        public void tryLock(){
            log.info("tryLock 尝试加锁...lock3、lock4、lock5");
            List list = new ArrayList<>();
            list.add("lock3");
            list.add("lock4");
            list.add("lock5");
            //加锁
            RLock multiLock = lockService.tryMultiLock(list);
            if(Objects.nonNull(multiLock)){
                log.info("tryLock 加锁成功,多锁为:lock3、lock4、lock5");
                try {
                    Thread.sleep(20000);
                }catch (Exception e){
                    log.error("休眠异常",e);
                }finally {
                    log.info("multiLock 开始解锁...");
                    multiLock.unlock();
                }
            } else {
                log.info("tryLock 尝试加锁失败...");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    测试步骤:

    1. 先执行multiLock()方法批量加锁 (lock1、lock2、lock3),在执行multiLock()加锁成功后5s内执行tryLock()尝试批量加锁(lock3、lock4、lock5),由于multiLock()中已经有lock3则tryLock批量加锁会全部失败,此时redis中会有3个key(lock1、lock2、lock3);
    2. 等待5s后multiLock()会执行解锁(此时redis中3个key也会同时被删掉),再执行tryLock()尝试批量加锁(lock3、lock4、lock5),则会加锁成功,此时redis中会有3个key(lock3、lock4、lock5);
    3. multiLock()加锁后等待10s,则会做解锁操作,同时redis中key(lock3、lock4、lock5)会删掉。

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    以上说明Redission的multiLock是完全支持批量加锁,并能保证批量加锁时的原子性(业务是在redis中用lua脚本实现);

  • 相关阅读:
    [Android]打开应用时导航栏闪烁问题分析
    MIPI CSI-2笔记(21) -- JPEG8数据格式
    分布式缓存--缓存与数据库一致性方案
    字符串的模式匹配算法
    设计模式(五):建造者模式
    Webpack Bundle Analyzer包分析器
    基于SpringBoot的墙绘产品展示交易平台设计与实现
    MySQL:基本概念和基础操作
    Java不定参数使用及一些注意情况
    .NET Conf China 2023分享-.NET应用国际化-AIGC智能翻译+代码生成
  • 原文地址:https://blog.csdn.net/qq_32979219/article/details/126784890