redisson分布式锁使用

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: Redisson 是一个高级的分布式协调 Redis 客服端,能帮助用户在分布式环境中轻松实现一些 Java 的对象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLo

简介

Redisson 是一个高级的分布式协调 Redis 客服端,能帮助用户在分布式环境中轻松实现一些 Java 的对象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。

image.png

适用场景

分布式应用,分布式缓存,分布式回话管理,分布式服务(任务,延迟任务,执行器),分布式 redis 客户端。

我们一般使用其分布式锁功能。

项目集成

添加依赖

image.png

引入依赖

image.png

代码示例

@Resource
private RedissonClient redissonClient;
/**
 * 抢购代金券
 *
 * @param voucherId   代金券 ID
 * @param accessToken 登录token
 * @Para path 访问路径
 */
@Transactional(rollbackFor = Exception.class)
public ResultInfo doSeckill(Integer voucherId, String accessToken, String path) {
    // 基本参数校验
    AssertUtil.isTrue(voucherId == null || voucherId < 0, "请选择需要抢购的代金券");
    AssertUtil.isNotEmpty(accessToken, "请登录");
    // ----------注释原始的走 关系型数据库 的流程----------
    // 判断此代金券是否加入抢购
    // SeckillVouchers seckillVouchers = seckillVouchersMapper.selectVoucher(voucherId);
    // AssertUtil.isTrue(seckillVouchers == null, "该代金券并未有抢购活动");
    // ----------采用 Redis 解问题----------
    String redisKey = RedisKeyConstant.seckill_vouchers.getKey() + voucherId;
    Map<String, Object> seckillVoucherMaps = redisTemplate.opsForHash().entries(redisKey);
    SeckillVouchers seckillVouchers = BeanUtil.mapToBean(seckillVoucherMaps, SeckillVouchers.class, true, null);
    // 判断是否有效
    AssertUtil.isTrue(seckillVouchers.getIsValid() == 0, "该活动已结束");
    // 判断是否开始、结束
    Date now = new Date();
    AssertUtil.isTrue(now.before(seckillVouchers.getStartTime()), "该抢购还未开始");
    AssertUtil.isTrue(now.after(seckillVouchers.getEndTime()), "该抢购已结束");
    // 判断是否卖完通过 Lua 脚本扣库存时判断
    //AssertUtil.isTrue(seckillVouchers.getAmount() < 1, "该券已经卖完了");
    // 获取登录用户信息
    String url = oauthServerName + "user/me?access_token={accessToken}";
    ResultInfo resultInfo = restTemplate.getForObject(url, ResultInfo.class, accessToken);
    if (resultInfo.getCode() != ApiConstant.SUCCESS_CODE) {
        resultInfo.setPath(path);
        return resultInfo;
    }
    // 这里的data是一个LinkedHashMap,SignInDinerInfo
    SignInDinerInfo dinerInfo = BeanUtil.fillBeanWithMap((LinkedHashMap) resultInfo.getData(),
            new SignInDinerInfo(), false);
    // 判断登录用户是否已抢到(一个用户针对这次活动只能买一次)
    VoucherOrders order = voucherOrdersMapper.findDinerOrder(dinerInfo.getId(),
            seckillVouchers.getFkVoucherId());
    AssertUtil.isTrue(order != null, "该用户已抢到该代金券,无需再抢");
    // ----------注释原始的走 关系型数据库 的流程----------
    // 扣库存
    // int count = seckillVouchersMapper.stockDecrease(seckillVouchers.getId());
    // AssertUtil.isTrue(count == 0, "该券已经卖完了");
    // 使用 Redis 锁一个账号只能购买一次
    String lockName = RedisKeyConstant.lock_key.getKey() + dinerInfo.getId() + ":" + voucherId;
    // 加锁
    long expireTime = seckillVouchers.getEndTime().getTime() - now.getTime();
    // 自定义 Redis 分布式锁
    // String lockKey = redisLock.tryLock(lockName, expireTime);
    // Redisson 分布式锁
    RLock lock = redissonClient.getLock(lockName);
    try {
        // 不为空意味着拿到锁了,执行下单
        // 自定义 Redis 分布式锁处理
        //if (StrUtil.isNotBlank(lockKey)) {
        // Redisson 分布式锁处理
        boolean isLocked = lock.tryLock(expireTime, TimeUnit.MILLISECONDS);
        if (isLocked) {
            // 下单
            VoucherOrders voucherOrders = new VoucherOrders();
            voucherOrders.setFkDinerId(dinerInfo.getId());
            // Redis 中不需要维护外键信息
            //voucherOrders.setFkSeckillId(seckillVouchers.getId());
            voucherOrders.setFkVoucherId(seckillVouchers.getFkVoucherId());
            String orderNo = IdUtil.getSnowflake(1, 1).nextIdStr();
            voucherOrders.setOrderNo(orderNo);
            voucherOrders.setOrderType(1);
            voucherOrders.setStatus(0);
            long count = voucherOrdersMapper.save(voucherOrders);
            AssertUtil.isTrue(count == 0, "用户抢购失败");
            // ----------采用 Redis 解问题----------
            // 扣库存
            // long count = redisTemplate.opsForHash().increment(redisKey, "amount", -1);
            // AssertUtil.isTrue(count < 0, "该券已经卖完了");
            // ----------采用 Redis + Lua 解问题----------
            // 扣库存
            List<String> keys = new ArrayList<>();
            keys.add(redisKey);
            keys.add("amount");
            Long amount = (Long) redisTemplate.execute(redisScript, keys);
            AssertUtil.isTrue(amount == null || amount < 1, "该券已经卖完了");
        }
    } catch (Exception e) {
        // 手动回滚事物
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        // 自定义 Redis 解锁
        // redisLock.unlock(lockName, lockKey);
        // Redisson 解锁
        lock.unlock();
        if (e instanceof ParameterException) {
            return ResultInfoUtil.buildError(0, "该券已经卖完了", path);
        }
    }
    return ResultInfoUtil.buildSuccess(path, "抢购成功");
}
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
6月前
|
运维 NoSQL 安全
Redisson分布式锁最基础内容
Redisson分布式锁最基础内容
51 0
|
1月前
|
运维 NoSQL Java
【Redis】6、Redisson 分布式锁的简单使用(可重入、重试机制...)
【Redis】6、Redisson 分布式锁的简单使用(可重入、重试机制...)
103 1
|
3月前
|
NoSQL 算法 安全
Redis 分布式锁的正确实现原理演化历程与 Redisson 实战总结
Redis 分布式锁的正确实现原理演化历程与 Redisson 实战总结
127 1
|
3月前
|
NoSQL Redis
Redis进阶- Redisson分布式锁实现原理及源码解析
Redis进阶- Redisson分布式锁实现原理及源码解析
76 0
|
3月前
|
NoSQL Java 中间件
如何使用Redisson实现分布式锁?
如何使用Redisson实现分布式锁?
215 1
|
5月前
|
缓存 NoSQL Redis
redisson实现分布式锁
redisson实现分布式锁
34 1
|
6月前
|
缓存 NoSQL API
分布式锁工具:Redisson,很强!
分布式锁工具:Redisson,很强!
115 1
|
6月前
|
分布式计算 NoSQL Java
Redisson—分布式服务
Redisson—分布式服务
81 1
|
6月前
|
缓存 NoSQL Java
Redisson—分布式集合
Redisson—分布式集合
66 1
|
7月前
|
NoSQL Java Redis
源码分析:Redisson分布式锁过程分析
本文基于Redisson3.12.2版本源码,对Redisson分布式锁过程进行了分析。从获取锁、释放锁的过程,可以大概了解Redisson的主要设计思想。此外,还对基于Jedis实现的一个分布式锁示例与Redisson进行对比,来看基于Redis的分布式锁的两种不同实现方式。
213 0

热门文章

最新文章