缓存-分布式锁-原理和基本使用

分布式锁原理和使用

 

自旋 

 public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {

        Boolean b = redisTemplate.opsForValue().setIfAbsent(Lock, Lock, Duration.ofMinutes(1));
        if (!b) {
            int i = 10;
            while (i > 0) {
                Object result = redisTemplate.opsForValue().get(CATALOG_JSON);
                try {
                    TimeUnit.MILLISECONDS.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                if (result != null) {
                    System.out.println("命中缓存 db lock");
                    return (Map<String, List<Catelog2Vo>>) result;
                }
                i--;
            }
            throw new RuntimeException("系统繁忙,请重新访问");
        }


        //1.查出所有1级分类
        List<CategoryEntity> selectList = baseMapper.selectList(null);
        /**
         * 将数据库的多次查询变成一次
         */
        System.out.println("查询了数据库");

        //2. 封装数据
        List<CategoryEntity> level1Category = selectList.stream().filter(s -> s.getParentCid().equals(0L)).collect(Collectors.toList());
        Map<String, List<Catelog2Vo>> map = level1Category.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
            //1.每一个的一级分类,查到1级分类的所有二级分类
            List<CategoryEntity> categoryEntities = selectList.stream().filter(s -> s.getParentCid().equals(v.getCatId())).collect(Collectors.toList());

            List<Catelog2Vo> catelog2VoList = categoryEntities.stream().map(c -> {
                Catelog2Vo catelog2Vo = new Catelog2Vo();
                catelog2Vo.setId(c.getCatId().toString());
                catelog2Vo.setName(c.getName());
                catelog2Vo.setCatalog1Id(v.getCatId().toString());

                List<CategoryEntity> categoryEntities1 = selectList.stream().filter(s -> s.getParentCid().equals(c.getCatId())).collect(Collectors.toList());
                List<Catelog2Vo.Catelog3Vo> collect = categoryEntities1.stream().map(c3 -> {
                    Catelog2Vo.Catelog3Vo catelog3Vo = new Catelog2Vo.Catelog3Vo();
                    catelog3Vo.setId(c3.getCatId().toString());
                    catelog3Vo.setName(c3.getName());
                    catelog3Vo.setCatalog2Id(c.getCatId().toString());
                    return catelog3Vo;
                }).collect(Collectors.toList());

                catelog2Vo.setCatalog3List(collect);

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


            return catelog2VoList;
        }));
        if (map == null) {
            /**
             * 解决缓存穿透
             */
            map = new HashMap<>();
        }
        redisTemplate.opsForValue().set(CATALOG_JSON, map, Duration.ofDays(1));
        redisTemplate.delete(Lock);
        return map;
    }

 public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {
        String uuid = UUID.randomUUID().toString();
        Boolean b = redisTemplate.opsForValue().setIfAbsent(Lock, uuid, Duration.ofMinutes(1));
        if (!b) {
            int i = 10;
            while (i > 0) {
                Object result = redisTemplate.opsForValue().get(CATALOG_JSON);
                try {
                    TimeUnit.MILLISECONDS.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                if (result != null) {
                    System.out.println("命中缓存 db lock");
                    return (Map<String, List<Catelog2Vo>>) result;
                }
                i--;
            }
            throw new RuntimeException("系统繁忙,请重新访问");
        }


        //1.查出所有1级分类
        List<CategoryEntity> selectList = baseMapper.selectList(null);
        /**
         * 将数据库的多次查询变成一次
         */
        System.out.println("查询了数据库");

        //2. 封装数据
        List<CategoryEntity> level1Category = selectList.stream().filter(s -> s.getParentCid().equals(0L)).collect(Collectors.toList());
        Map<String, List<Catelog2Vo>> map = level1Category.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
            //1.每一个的一级分类,查到1级分类的所有二级分类
            List<CategoryEntity> categoryEntities = selectList.stream().filter(s -> s.getParentCid().equals(v.getCatId())).collect(Collectors.toList());

            List<Catelog2Vo> catelog2VoList = categoryEntities.stream().map(c -> {
                Catelog2Vo catelog2Vo = new Catelog2Vo();
                catelog2Vo.setId(c.getCatId().toString());
                catelog2Vo.setName(c.getName());
                catelog2Vo.setCatalog1Id(v.getCatId().toString());

                List<CategoryEntity> categoryEntities1 = selectList.stream().filter(s -> s.getParentCid().equals(c.getCatId())).collect(Collectors.toList());
                List<Catelog2Vo.Catelog3Vo> collect = categoryEntities1.stream().map(c3 -> {
                    Catelog2Vo.Catelog3Vo catelog3Vo = new Catelog2Vo.Catelog3Vo();
                    catelog3Vo.setId(c3.getCatId().toString());
                    catelog3Vo.setName(c3.getName());
                    catelog3Vo.setCatalog2Id(c.getCatId().toString());
                    return catelog3Vo;
                }).collect(Collectors.toList());

                catelog2Vo.setCatalog3List(collect);

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


            return catelog2VoList;
        }));
        if (map == null) {
            /**
             * 解决缓存穿透
             */
            map = new HashMap<>();
        }
        redisTemplate.opsForValue().set(CATALOG_JSON, map, Duration.ofDays(1));
        Object o = redisTemplate.opsForValue().get(Lock);
        if (o != null && o.equals(uuid)) {
            redisTemplate.delete(Lock);
        }

        return map;
    }

还是有问题

因为 在传输过程中需要耗时,这时候如果过期KEY,让其他线程进来创建KEY,然后数据返回到之前那个线程,删除KEY,又会把别人新加进来的key给删掉

获取值对比+对比成功删除=原子操作

 redis+lua脚本实现

 public static final String Lock = "Lock";
  public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {
        String uuid = UUID.randomUUID().toString();
        Boolean b = redisTemplate.opsForValue().setIfAbsent(Lock, uuid, Duration.ofMinutes(5));
        if (!b) {
            System.out.println("获取分布式锁失败,等待重试");
            int i = 10;
            while (i > 0) {
                Object result = redisTemplate.opsForValue().get(CATALOG_JSON);
                try {
                    TimeUnit.MILLISECONDS.sleep(100);
                } catch (InterruptedException e) {
                   e.printStackTrace();
                }
                if (result != null) {
                    System.out.println("命中缓存 db lock");
                    return (Map<String, List<Catelog2Vo>>) result;
                }
                i--;
            }
            throw new RuntimeException("系统繁忙,请重新访问");
        }


        //1.查出所有1级分类
        /**
         * 将数据库的多次查询变成一次
         */
        System.out.println("获取分布式锁成功");

        //2. 封装数据
        Map<String, List<Catelog2Vo>> map = null;
        try {
            System.out.println("查询了数据库");
            List<CategoryEntity> selectList = baseMapper.selectList(null);
            List<CategoryEntity> level1Category = selectList.stream().filter(s -> s.getParentCid().equals(0L)).collect(Collectors.toList());
            map = level1Category.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
                //1.每一个的一级分类,查到1级分类的所有二级分类
                List<CategoryEntity> categoryEntities = selectList.stream().filter(s -> s.getParentCid().equals(v.getCatId())).collect(Collectors.toList());

                List<Catelog2Vo> catelog2VoList = categoryEntities.stream().map(c -> {
                    Catelog2Vo catelog2Vo = new Catelog2Vo();
                    catelog2Vo.setId(c.getCatId().toString());
                    catelog2Vo.setName(c.getName());
                    catelog2Vo.setCatalog1Id(v.getCatId().toString());

                    List<CategoryEntity> categoryEntities1 = selectList.stream().filter(s -> s.getParentCid().equals(c.getCatId())).collect(Collectors.toList());
                    List<Catelog2Vo.Catelog3Vo> collect = categoryEntities1.stream().map(c3 -> {
                        Catelog2Vo.Catelog3Vo catelog3Vo = new Catelog2Vo.Catelog3Vo();
                        catelog3Vo.setId(c3.getCatId().toString());
                        catelog3Vo.setName(c3.getName());
                        catelog3Vo.setCatalog2Id(c.getCatId().toString());
                        return catelog3Vo;
                    }).collect(Collectors.toList());

                    catelog2Vo.setCatalog3List(collect);

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


                return catelog2VoList;
            }));
            if (map == null) {
                /**
                 * 解决缓存穿透
                 */
                map = new HashMap<>();
            }
            redisTemplate.opsForValue().set(CATALOG_JSON, map, Duration.ofDays(1));


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //lua脚本解锁
            //如果获取key等于传过来的值,就执行删除操作,否则就不执行
            String script="if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
            Long execute = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(Lock), uuid);
            if (execute==1){
                System.out.println("原子删锁成功");
            }else {
                System.out.println("原子删锁失败");
            }
        }

        return map;
    }

 只有一个查询了数据库

相关推荐

  1. 缓存】一、Redis的基本使用与Redisson分布式

    2024-07-10 19:44:03       41 阅读
  2. 【Redis】Redis分布式基本原理具体实现

    2024-07-10 19:44:03       33 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 19:44:03       99 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 19:44:03       107 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 19:44:03       90 阅读
  4. Python语言-面向对象

    2024-07-10 19:44:03       98 阅读

热门阅读

  1. How to Describe Figures in a Research Article

    2024-07-10 19:44:03       20 阅读
  2. 常见网络攻击方式及防御方法

    2024-07-10 19:44:03       21 阅读
  3. Amazon Bedrock 常用权限分类详解

    2024-07-10 19:44:03       23 阅读
  4. Emacs有什么优点,用Emacs写程序真的比IDE更方便吗?

    2024-07-10 19:44:03       23 阅读
  5. AWS Glue 与 Amazon Redshift 的安全通信配置

    2024-07-10 19:44:03       26 阅读
  6. Elasticsearch7.5.2 常用rest api与elasticsearch库

    2024-07-10 19:44:03       26 阅读
  7. MySQL 的 Buffer Pool 的结构及有什么作用

    2024-07-10 19:44:03       27 阅读