【业务功能100】补充代码【业务功能88】微服务-springcloud-分布式锁-redis-redisson-springcache

news/2025/1/16 5:46:12/

采用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;}

http://www.ppmy.cn/news/1095782.html

相关文章

HTTP代理协议原理分析

HTTP代理协议是一种常见的网络协议&#xff0c;它可以在网络中传递HTTP协议的请求和响应。本文将介绍HTTP代理协议的分析和原理&#xff0c;包括HTTP代理的工作流程、HTTP代理的请求和响应格式、HTTP代理的优缺点等方面。 一、HTTP代理的工作流程 HTTP代理的工作流程如下&#…

ElementUI浅尝辄止33:Form 表单

Form 表单&#xff1a;日常业务中很常见&#xff0c;由输入框、选择器、单选框、多选框等控件组成&#xff0c;用以收集、校验、提交数据&#xff0c;常见于表单请求、登录&#xff0c;数据校验等业务操作中 1.如何使用&#xff1f; 包括各种表单项&#xff0c;比如输入框、选…

生存游戏手游推荐,适合长期玩的生存类手游

今天小编为大家带来了生存游戏手游推荐&#xff0c;适合长期玩的生存类手游。许多朋友现在喜欢冒险&#xff0c;想体验荒野生活&#xff0c;但在现实中&#xff0c;由于各种原因可能实现不了。游戏中的生存可以满足玩家对狂野生存的幻想&#xff0c;让现实中未实现的梦想在虚拟…

国产信创服务器如何进行安全可靠的文件传输?

信创&#xff0c;即信息技术应用创新&#xff0c;2018年以来&#xff0c;受“华为、中兴事件”影响&#xff0c;国家将信创产业纳入国家战略&#xff0c;并提出了“28n”发展体系。从产业链角度&#xff0c;信创产业生态体系较为庞大&#xff0c;主要包括基础硬件、基础软件、应…

【Rust日报】2023-09-06 Grillon - API 测试框架

Grillon - API 测试框架 优雅、直观和富有表现力的 API内置测试功能支持扩展 用法&#xff1a; use grillon::{dsl::*, dsl::http::*, json, Grillon, StatusCode, Result}; use grillon::header::{HeaderValue, CONTENT_LENGTH, CONTENT_TYPE};#[tokio::test] async fn end_to…

接口自动化测试总结

一、什么项目适合做自动化测试&#xff1f; 软件需求变动不频繁 测试脚本的稳定性决定了自动化测试的维护成本。如果软件需求变动过于频繁&#xff0c;测试人员需要根据变动的需求来更新测试用例以及相关的测试脚本&#xff0c;而脚本的维护本身就是一个代码开发的过程&#x…

Git版本管理

Git版本介绍 Git 是一个分布式版本控制系统&#xff0c;它被广泛用于协作软件开发和管理代码的变更。Git 的设计目标是为了处理速度快、灵活性强、数据完整性好的版本管理需求。以下是 Git 版本管理的详细介绍&#xff1a; 版本控制系统 (VCS)&#xff1a; Git 是一种版本控制…

我发现了一个很好看的字体,霞鹜文楷!如何换windows和typora字体?

1、字体 官方地址如下&#xff0c;下载也很简单。 https://github.com/lxgw/LxgwWenKai 有1W多的stars。 方式&#xff1a; 直接打包下载。下载不来&#xff0c;可以联系在下面留言。 然后ttf的文件&#xff0c;全部安装就行了。 2、更换系统字体 然后换windows系统的字…