采用redisson做分布式锁,完成数据的查询接口功能getCatelog2JSONRedis
原先从mysql数据库查询的效率较低,现在将部分固定数据展示比如页面的树形栏目信息等,存储到redis缓存,然后基于分布式集群,需要结合本地锁(synchronized )与分布式锁(redissonClient.getLock(“catelog2JSON-lock”)),避免多次重复访问数据库
/*** 查询出所有的二级和三级分类的数据* 并封装为Map<String, Catalog2VO>对象* @return*///@Overridepublic Map<String, List<Catalog2VO>> getCatelog2JSONRedis() {String key = "catalogJSON";// 从Redis中获取分类的信息String catalogJSON = stringRedisTemplate.opsForValue().get(key);if(StringUtils.isEmpty(catalogJSON)){System.out.println("缓存没有命中.....");// 缓存中没有数据,需要从数据库中查询Map<String, List<Catalog2VO>> catelog2JSONForDb = getCatelog2JSONDbWithRedisson();return catelog2JSONForDb;}System.out.println("缓存命中了....");// 表示缓存命中了数据,那么从缓存中获取信息,然后返回Map<String, List<Catalog2VO>> stringListMap = JSON.parseObject(catalogJSON, new TypeReference<Map<String, List<Catalog2VO>>>() {});return stringListMap;}public Map<String, List<Catalog2VO>> getCatelog2JSONDbWithRedisson() {String keys = "catalogJSON";// 获取分布式锁对象 加锁的时候,这个锁的名称一定要注意// 商品信息 product-lock product-1001-lock product-1002-lockRLock lock = redissonClient.getLock("catelog2JSON-lock");Map<String, List<Catalog2VO>> data = null;try {lock.lock();// 加锁成功data = getDataForDB(keys);}finally {lock.unlock();}return data;}/*** 从数据库中查询操作* @param keys* @return*/private Map<String, List<Catalog2VO>> getDataForDB(String keys) {// 从Redis中获取分类的信息String catalogJSON = stringRedisTemplate.opsForValue().get(keys);if(!StringUtils.isEmpty(catalogJSON)){// 说明缓存命中// 表示缓存命中了数据,那么从缓存中获取信息,然后返回Map<String, List<Catalog2VO>> stringListMap = JSON.parseObject(catalogJSON, new TypeReference<Map<String, List<Catalog2VO>>>() {});return stringListMap;}System.out.println("-----------》查询数据库操作");// 获取所有的分类数据List<CategoryEntity> list = baseMapper.selectList(new QueryWrapper<CategoryEntity>());// 获取所有的一级分类的数据List<CategoryEntity> leve1Category = this.queryByParenCid(list,0l);// 把一级分类的数据转换为Map容器 key就是一级分类的编号, value就是一级分类对应的二级分类的数据Map<String, List<Catalog2VO>> map = leve1Category.stream().collect(Collectors.toMap(key -> key.getCatId().toString(), value -> {// 根据一级分类的编号,查询出对应的二级分类的数据List<CategoryEntity> l2Catalogs = this.queryByParenCid(list,value.getCatId());List<Catalog2VO> Catalog2VOs =null;if(l2Catalogs != null){Catalog2VOs = l2Catalogs.stream().map(l2 -> {// 需要把查询出来的二级分类的数据填充到对应的Catelog2VO中Catalog2VO catalog2VO = new Catalog2VO(l2.getParentCid().toString(), null, l2.getCatId().toString(), l2.getName());// 根据二级分类的数据找到对应的三级分类的信息List<CategoryEntity> l3Catelogs = this.queryByParenCid(list,l2.getCatId());if(l3Catelogs != null){// 获取到的二级分类对应的三级分类的数据List<Catalog2VO.Catalog3VO> catalog3VOS = l3Catelogs.stream().map(l3 -> {Catalog2VO.Catalog3VO catalog3VO = new Catalog2VO.Catalog3VO(l3.getParentCid().toString(), l3.getCatId().toString(), l3.getName());return catalog3VO;}).collect(Collectors.toList());// 三级分类关联二级分类catalog2VO.setCatalog3List(catalog3VOS);}return catalog2VO;}).collect(Collectors.toList());}return Catalog2VOs;}));// 从数据库中获取到了对应的信息 然后在缓存中也存储一份信息//cache.put("getCatelog2JSON",map);// 表示缓存命中了数据,那么从缓存中获取信息,然后返回if(map == null){// 那就说明数据库中也不存在 防止缓存穿透stringRedisTemplate.opsForValue().set(keys,"1",5, TimeUnit.SECONDS);}else{// 从数据库中查询到的数据,我们需要给缓存中也存储一份// 防止缓存雪崩String json = JSON.toJSONString(map);stringRedisTemplate.opsForValue().set("catalogJSON",json,100,TimeUnit.MINUTES);}return map;}/*** 从数据库查询的结果* 查询出所有的二级和三级分类的数据* 并封装为Map<String, Catalog2VO>对象* 在SpringBoot中,默认的情况下是单例* @return*/public Map<String, List<Catalog2VO>> getCatelog2JSONForDb() {String keys = "catalogJSON";//synchronized 加本地锁,即使分布式集群,本地服务也需要加上本地锁synchronized 或者其他锁,避免大量并发访问直接走到分布式锁造成压力synchronized (this){// 从Redis中获取分类的信息String catalogJSON = stringRedisTemplate.opsForValue().get(keys);if(!StringUtils.isEmpty(catalogJSON)){// 说明缓存命中// 表示缓存命中了数据,那么从缓存中获取信息,然后返回Map<String, List<Catalog2VO>> stringListMap = JSON.parseObject(catalogJSON, new TypeReference<Map<String, List<Catalog2VO>>>() {});return stringListMap;}System.out.println("-----------》查询数据库操作");// 获取所有的分类数据List<CategoryEntity> list = baseMapper.selectList(new QueryWrapper<CategoryEntity>());// 获取所有的一级分类的数据List<CategoryEntity> leve1Category = this.queryByParenCid(list,0l);// 把一级分类的数据转换为Map容器 key就是一级分类的编号, value就是一级分类对应的二级分类的数据Map<String, List<Catalog2VO>> map = leve1Category.stream().collect(Collectors.toMap(key -> key.getCatId().toString(), value -> {// 根据一级分类的编号,查询出对应的二级分类的数据List<CategoryEntity> l2Catalogs = this.queryByParenCid(list,value.getCatId());List<Catalog2VO> Catalog2VOs =null;if(l2Catalogs != null){Catalog2VOs = l2Catalogs.stream().map(l2 -> {// 需要把查询出来的二级分类的数据填充到对应的Catelog2VO中Catalog2VO catalog2VO = new Catalog2VO(l2.getParentCid().toString(), null, l2.getCatId().toString(), l2.getName());// 根据二级分类的数据找到对应的三级分类的信息List<CategoryEntity> l3Catelogs = this.queryByParenCid(list,l2.getCatId());if(l3Catelogs != null){// 获取到的二级分类对应的三级分类的数据List<Catalog2VO.Catalog3VO> catalog3VOS = l3Catelogs.stream().map(l3 -> {Catalog2VO.Catalog3VO catalog3VO = new Catalog2VO.Catalog3VO(l3.getParentCid().toString(), l3.getCatId().toString(), l3.getName());return catalog3VO;}).collect(Collectors.toList());// 三级分类关联二级分类catalog2VO.setCatalog3List(catalog3VOS);}return catalog2VO;}).collect(Collectors.toList());}return Catalog2VOs;}));// 从数据库中获取到了对应的信息 然后在缓存中也存储一份信息//cache.put("getCatelog2JSON",map);// 表示缓存命中了数据,那么从缓存中获取信息,然后返回if(map == null){// 那就说明数据库中也不存在 防止缓存穿透stringRedisTemplate.opsForValue().set(keys,"1",5, TimeUnit.SECONDS);}else{// 从数据库中查询到的数据,我们需要给缓存中也存储一份// 防止缓存雪崩String json = JSON.toJSONString(map);stringRedisTemplate.opsForValue().set("catalogJSON",json,100,TimeUnit.MINUTES);}return map;} }
采用springcache 注解方式进行缓存处理
与业务逻辑解耦,使用更方便
springcache底层没有采用分布式锁去避免了大量访问进数据库,造成缓存击穿,但是使用了 synchronized
本地同步锁,这样如果是分布式集群有三台,那么每个节点都是只会有一个请求去访问,即使都去访问了数据库,这样压力也不会很大
@Cacheable(value = "catagory",key = "#root.methodName")@Overridepublic Map<String, List<Catalog2VO>> getCatelog2JSON() {// 获取所有的分类数据List<CategoryEntity> list = baseMapper.selectList(new QueryWrapper<CategoryEntity>());// 获取所有的一级分类的数据List<CategoryEntity> leve1Category = this.queryByParenCid(list,0l);// 把一级分类的数据转换为Map容器 key就是一级分类的编号, value就是一级分类对应的二级分类的数据Map<String, List<Catalog2VO>> map = leve1Category.stream().collect(Collectors.toMap(key -> key.getCatId().toString(), value -> {// 根据一级分类的编号,查询出对应的二级分类的数据List<CategoryEntity> l2Catalogs = this.queryByParenCid(list,value.getCatId());List<Catalog2VO> Catalog2VOs =null;if(l2Catalogs != null){Catalog2VOs = l2Catalogs.stream().map(l2 -> {// 需要把查询出来的二级分类的数据填充到对应的Catelog2VO中Catalog2VO catalog2VO = new Catalog2VO(l2.getParentCid().toString(), null, l2.getCatId().toString(), l2.getName());// 根据二级分类的数据找到对应的三级分类的信息List<CategoryEntity> l3Catelogs = this.queryByParenCid(list,l2.getCatId());if(l3Catelogs != null){// 获取到的二级分类对应的三级分类的数据List<Catalog2VO.Catalog3VO> catalog3VOS = l3Catelogs.stream().map(l3 -> {Catalog2VO.Catalog3VO catalog3VO = new Catalog2VO.Catalog3VO(l3.getParentCid().toString(), l3.getCatId().toString(), l3.getName());return catalog3VO;}).collect(Collectors.toList());// 三级分类关联二级分类catalog2VO.setCatalog3List(catalog3VOS);}return catalog2VO;}).collect(Collectors.toList());}return Catalog2VOs;}));return map;}