首页 > 其他分享 >70、缓存---分布式锁---分布式锁的原理及使用

70、缓存---分布式锁---分布式锁的原理及使用

时间:2023-01-31 21:25:16浏览次数:47  
标签:map getCatId 分类 --- collect 线程 70 new 分布式

阶段一

代码如下:

private Map<String, List<CatelogTwoLevelVo>> getCatalogJsonFromDb() {
        //得到锁之后,去缓存中再确定一次是否有数据
        String catalogJson = redisTemplate.opsForValue().get("catalogJson");
        if (!StringUtils.isEmpty(catalogJson)) {//缓存中有数据
            Map<String, List<CatelogTwoLevelVo>> result = JSON.parseObject(catalogJson, new TypeReference<Map<String, List<CatelogTwoLevelVo>>>() {
            });
            return result;
        }

        //查询所有的一级分类
        List<CategoryEntity> categoryEntities = this.selectOneLevelCategory();

        //查询所有的二级分类和三级分类并封装数据
        //map的key是一级分类的id,v是二级分类的vo
        Map<String, List<CatelogTwoLevelVo>> map = categoryEntities.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
            //查询每一个一级分类下的二级分类
            List<CategoryEntity> categoryTwoLevelEntities = this.baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", v.getCatId()));
            List<CatelogTwoLevelVo> collect = null;
            if (categoryTwoLevelEntities != null) {
                collect = categoryTwoLevelEntities.stream().map(l2 -> {
                    //查询该二级分类对应的三级分类并封装数据
                    List<CategoryEntity> categoryThreeLevelEntities = this.baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", l2.getCatId()));
                    List<CatelogTwoLevelVo.CatalogThreeLevelVo> catalogThreeLevelVos = null;
                    if (categoryThreeLevelEntities != null) {
                        catalogThreeLevelVos = categoryThreeLevelEntities.stream().map(l3 -> {
                            CatelogTwoLevelVo.CatalogThreeLevelVo catalogThreeLevelVo = new CatelogTwoLevelVo.CatalogThreeLevelVo(l2.getCatId().toString(), l3.getCatId().toString(), l3.getName());

                            return catalogThreeLevelVo;
                        }).collect(Collectors.toList());
                    }
                    //构造二级分类的vo
                    CatelogTwoLevelVo catelogTwoLevelVo = new CatelogTwoLevelVo(v.getCatId().toString(), catalogThreeLevelVos, l2.getCatId().toString(), l2.getName());

                    return catelogTwoLevelVo;
                }).collect(Collectors.toList());
            }
            return collect;
        }));

        String s = JSON.toJSONString(map);
        int minutes = 1440 + new Random().nextInt(10);//过期时间:1天(1440分钟)加上随机数
        redisTemplate.opsForValue().set("catalogJson", s, minutes, TimeUnit.MINUTES);//存入缓存

        return map;
    }

但是存在问题:如果一个线程在redis中站好了坑位,但是业务代码执行出现异常,有可能不会解锁,这就可能导致其余线程都没法获得锁,也就获取不到数据。即使我们处理异常,在finally中进行解锁,如果发生停电宕机,也会出现解锁不成功的情况
解决办法:给锁添加过期时间

阶段二


但是存在问题:在我们设置过期时间之前突然宕机,又会陷入死循环,没有线程能获取锁
因此加锁和设置过期时间必须是一个原子操作;

阶段三


但是存在问题:如果我们的业务代码执行时间比较长,在我们删除锁之前,我们之前设置的锁已经自己过期了。现在redis中的锁是别的线程的锁,这样我们就删除了别人的锁。因此使用uuid区分每个线程的锁

阶段四


但是存在问题:我们删除锁是先获取值进行对比,然后对比成功才删除锁。如果我们对比成功了,恰好进入了if,但是此时我们的锁正好到时间过期了,别的进行又立刻占了一个锁,这时我们删除的锁就不是自己的锁。就会导致有一个线程抢到锁,即没锁住。因此,获取值+删除锁应该是一个原子操作

阶段五:最终形态
使用lua脚本来完成原子解锁
官方文档如下:

代码如下:

分布式锁还有更专业框架,在下面文章中有记载

标签:map,getCatId,分类,---,collect,线程,70,new,分布式
From: https://www.cnblogs.com/morehair/p/17080782.html

相关文章

  • mybatis实现批量插入更新 -- ON DUPLICATE KEY UPDATE
    必须保证有唯一索引,可以是主键索引或者组合索引<insertid="insertOrUpdate"parameterType="java.util.List">INSERTINTOindicators_template_detail_rep(......
  • 心理学-森田疗法
    2.【安大雄】https://www.bilibili.com/video/BV1Wo4y1d7QH/?spm_id_from=333.337.search-card.all.click&vd_source=08f2fe3f5caa2d2714e8d9d3d972cbf1......
  • 多线程--消费者与生产者实例
    多线程实例1.消费者与生产者实例(管程法)产品、消费者、生产者、缓冲区产品,保证有一个唯一标识即可消费者继承Thread,注册缓冲区,从缓冲区消费生产者继承Thread,注册缓冲......
  • 代码随想录(2)-链表
    题单203.移除链表元素链表节点对象publicclassListNode{//结点的值intval;//下一个结点ListNodenext;//节点的构造函数(无参)......
  • 2023-01-31 量学基础 九阴真经 74
    1.三个基本因素(1)价格:阴过阳,阴盖阳,双阴盖阳(2)成交量:平量,小倍量,倍量(3)量线:平衡线,斜横线,平斜线2.有2个条件满足,减半仓,3个条件都满足,全出!         ......
  • drf-restful规范、django原生编写接口
    1.restful规范REST全称是RepresentationalStateTransfer,中文意思是表述:表征性状态转移,它首次出现在2000年RoyFielding的博士论文中。RESTful是一种定义WebAPI接口的设......
  • 心理学-强迫性重复
    https://www.bilibili.com/video/BV1mZ4y197DX/?spm_id_from=333.337.search-card.all.click&vd_source=08f2fe3f5caa2d2714e8d9d3d972cbf1......
  • 字符设备驱动-3.gpio驱动(按键中断)
    APP读取按键查询方式休眠-唤醒方式poll方式异步通知方式第2、3、4种方法,都涉及中断服务程序。查询方式APP调用open时,导致驱动中对应的open函数被调用,在里......
  • 运维百家讲坛第1期:井源 - 运维几何
    编者著:井老板是我11年入行加入百度时的团队大老板,骨灰级老炮,逮着这个机会不容易,把业内常见问题都问了个遍,以飨读者。井老板生性洒脱,嬉笑怒骂皆成文章,道理自在其中。这里是接......
  • 物理实验网站--物理猫网站
    物理猫网站不错,可以做演示实验:比如:凸透镜成像动态演示https://www.phycat.cn/archives/97/【中考物理】我是这样记住凸透镜成像规律的https://www.bilibili.com/video/BV......