Redisson-MultiLock使用

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

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

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

        
        
            org.redisson
            redisson-spring-boot-starter
            3.16.4
        

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

}

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

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. 先执行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)会删掉。

Redisson-MultiLock使用_第1张图片
Redisson-MultiLock使用_第2张图片
Redisson-MultiLock使用_第3张图片

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

你可能感兴趣的:(redis,java,开发语言)