综合中间件Redisson(三)分布式锁实战

综合中间件Redisson(三)分布式锁实战

重温分布式锁

前面的文章说过,分布式锁的出现是为了解决跨JVM,多台服务器共享一个资源的问题,避免并发出现数据不安全,数据不一致的问题。
本章我们讲述的分布式锁是使用Redisson实现的,其提供了分布式锁的功能组件,可以用来弥补基于 Redis的原子性操作的缺陷,下面分析基于Redis实现分布式锁的不足之处。
比如,如果redis负责存储分布式锁的节点发生了宕机的情况 ,但是该锁又是处于被锁住的状态,这种情况就会出现死锁。为了避免这种情况,Redisson提供了个监控锁的“看门狗”,作用是在Redisson实例被关闭之前,不断延长分布式锁的有效期,默认情况下,这个时间 是30秒,当然我们可以通过Config.lockWarchDogTimeout进行设置。
Redisson为我们提供了多个同业务场景的锁,根据功能特性,我们可以分成可重入锁公平锁联锁红锁读写锁,**信号量 **,闭锁
下面介绍可重入锁
在这里插入图片描述

分布式锁之一次性锁

这种一次性锁是在某一个时间段内,只能允许一个线程共享资源,其他的线程统统打回,这种业务场景适用于,“用户注册 ”,“抢红包”,“重复提交”,下面我们验证用于 “重复提交”

    @RequestMapping("/testRedissonOnceLock")
    public ResultVo testRedissonOnceLock(@RequestBody UserLoginDto userLoginDto) {
        // 定义锁的名字
        String key = "redisson:myOnceLock" + userLoginDto.getUserName();
        // 获取分布式锁(一次性的)
        RLock rLock = redissonClient.getLock(key);
        // 一次性锁
        rLock.lock(1L,TimeUnit.SECONDS);
        // 根据 用户名称查询账号
        UserReg userReg = userRegMapper.selectByUserName(userLoginDto.getUserName());
        if (userReg == null) {
            UserReg insertUserReg = new UserReg(){
                {
                    setCreateTime(new Date());
                    setPassword(userLoginDto.getPassword());
                    setUserName(userLoginDto.getUserName());
                }
            };
            userRegMapper.insertSelective(insertUserReg);
            log.info("{}注册成功",userLoginDto.getUserName());
            return ResultVo.success("注册成功");
        }
        rLock.forceUnlock();
        return ResultVo.success();
    }

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

分布式锁之可重入锁

可重入锁就是当线程 获取不到锁 的时候会等待一段时间,重新去尝试获取锁,如果不能获取锁 ,并且重试的时间达到了上限,则 意味着 该线程就会 被抛弃 。
这种场景适用于同一时刻并发产生很多线程,但是同一时刻不能获取到分布式锁,但是却允许隔一定的时间后重新获取到,典型的应用场景就是商城高并发抢购,比如防止超库。
在这里插入图片描述

    @RequestMapping("/testReplyRedissonLock")
    public ResultVo testReplyRedissonLock(@RequestBody BookRobDto dto) {
        String key = "Replylock" + dto.getBookNo() + "_" + dto.getUserId();
        // 获取分布式锁
        RLock lock=redissonClient.getLock(key);
        // 尝试获取分布式锁,如果返回true,即代表成功获取了分布式锁
        try {
            log.info("开始抢购");
            boolean result = lock.tryLock(100,5L,TimeUnit.SECONDS);
            if (result) {
                // 判断此书籍是否能够被抢购
                BookStock bookStock = bookStockMapper.selectBookRobByBookNo(dto.getBookNo());
                if (bookStock == null || Integer.valueOf(bookStock.getStock()) <= 0) {
                    return ResultVo.error("库存不足");
                }
                // 先查询用户是否抢购过此书籍
                Integer buyedTotal = bookRobMapper.countByBookNoUserId(dto.getUserId(), dto.getBookNo());
                if (buyedTotal > 0) {
                    return ResultVo.error("您已抢购过该书籍");
                }
                bookStock.setStock(String.valueOf(Integer.valueOf(bookStock.getStock()) - 1));
                log.info("更新之前的库存" + bookStock.getStock());
                int res = bookStockMapper.updateStockWithLock(dto.getBookNo());
                log.info("更新库存完成");
                if (res > 0 ) {
                    // 创建书籍抢购记录实体信息
                    BookRob entity = new BookRob();
                    // 从提交的用户抢购请求实体信息中对应的字段取值
                    // 复制到新创建的书籍抢购记录实体的相应字段中
                    BeanUtils.copyProperties(dto,entity);
                    // 设置抢购时间
                    entity.setRobTime(new Date());
                    // 插入用户注册信息
                    bookRobMapper.insertSelective(entity);
                    log.info("插入抢购记录成功");
                }
                return ResultVo.success("抢购成功");
            }else {
                log.error("库存不足1");
            }
        } catch (InterruptedException e) {
            return ResultVo.error("异常");
        } finally {
            // 释放锁
            lock.forceUnlock();
        }
        return ResultVo.error("抢购失败");
    }
  <update id="updateStockWithLock">
   update book_stock SET stock = stock - 1
   where isActive=1 AND book_no=#{bookNo} and stock > 0 and (stock -1)>=0
 </update>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值