当前位置: 首页 > news >正文

广东网站建设制作价格贵阳中国建设银行招聘信息网站

广东网站建设制作价格,贵阳中国建设银行招聘信息网站,防红短网址在线生成,如何推广我的网站文章目录 外卖项目优化-01课程内容前言1. 环境搭建1.1 版本控制解决branch和tag命名冲突 1.2 环境准备 2. 缓存短信验证码2.1 思路分析2.2 代码改造2.3 功能测试 3. 缓存菜品信息3.1 实现思路3.2 代码改造3.2.1 查询菜品缓存3.2.2 清理菜品缓存 3.3 功能测试3.4 提交并推送代码… 文章目录 外卖项目优化-01课程内容前言1. 环境搭建1.1 版本控制解决branch和tag命名冲突 1.2 环境准备 2. 缓存短信验证码2.1 思路分析2.2 代码改造2.3 功能测试 3. 缓存菜品信息3.1 实现思路3.2 代码改造3.2.1 查询菜品缓存3.2.2 清理菜品缓存 3.3 功能测试3.4 提交并推送代码 4. SpringCache4.1 介绍4.2 注解4.3 入门程序4.3.1 环境准备4.3.2 CachePut注解4.3.3 CacheEvict注解4.3.4 Cacheable注解 4.4 集成Redis 5. 缓存套餐数据5.1 实现思路5.2 缓存套餐数据5.2.1 代码实现5.2.2 测试 5.3 清理套餐数据5.3.1 代码实现5.3.2 测试5.3.3 其他功能缓存处理 5.4 提交推送代码 外卖项目优化-01 课程内容 环境搭建缓存短信验证码缓存菜品信息SpringCache缓存套餐数据 前言 1). 当前系统存在的问题 之前我们已经实现了移动端菜品展示、点餐、购物车、下单等功能但是由于移动端是面向所有的消费者的请求压力相对比较大而我们当前所有的数据查询都是从数据库MySQL中直接查询的那么可能就存在如下问题 频繁访问数据库数据库访问压力大系统性能下降用户体验较差。 2). 解决该问题的方法 要解决我们上述提到的问题就可以使用我们前面学习的一个技术Redis通过Redis来做缓存从而降低数据库的访问压力提高系统的访问性能从而提升用户体验。加入Redis做缓存之后我们在进行数据查询时就需要先查询缓存如果缓存中有数据直接返回如果缓存中没有数据则需要查询数据库再将数据库查询的结果缓存在redis中。 1. 环境搭建 1.1 版本控制 接下来我们就需要对我们的功能进行优化但是需要说明的是我们不仅仅要对上述提到的缓存进行优化还需要对我们程序的各个方面进行优化。我们本章节主要是针对于缓存进行优化为了方便的对我们各个优化版本的代码进行管理我们使用Git来控制代码版本。 那么此时我们就需要将我们之前开发完成的代码提交到Git并且推送到码云Gitee的远程仓库执行步骤如下 其实之前学习完git时有些操作我已经做过了这里有些操作就可以忽略了 1). 创建Gitee远程仓库 2). idea-创建本地仓库 3). 准备忽略文件.gitignore 在我们的项目中, 有一些文件是无需提交的到git比如: .ideatarget/*.iml等。我们可以直接将今天课程资料中提供的.gitignore 文件导入到我们的项目中。 我之前的忽略文件感觉没有教程的丰富内容就替换成教程的吧 4). idea-提交并推送本地代码 A. 添加项目文件进暂存区 就是add操作 B. 提交代码 就是commit操作 C. 推送代码到远程仓库 就是push操作 5). 查看gitee远程仓库 看一下我最新的吧 我已经打好了一个标签了 没想到教程标准做法是直接创建一个新分支也确实是啊到时候想回到刚开发好的状态直接切换到主分支即可想看看优化后的项目直接切换到马上要创建的新分支即可。多方便啊 6). 创建分支 目前默认git中只有一个主分支master我们接下来进行缓存的优化就不在master分支来操作了我们需要在git上创建一个单独的分支v1.0缓存的优化我们就在该分支上进行操作。 创建完成后自动切换到v1.0分支了当前代码状态和master还是完全一样 但是接下来所有的操作都是在此分支下做的不会影响到master分支了 先在v1.0分支上开发测试通过后发现没问题再给他合并到master主分支 当前创建的v1.0分支是基于master分支创建出来的所以目前master分支的代码 和v1.0分支的代码是完全一样的接下来把v1.0的代码也推送至远程仓库。 解决branch和tag命名冲突 千万注意分支branch和标签tag不能重名否则push时会报错 打算以后tag都用v1.0.x的形式 而 branch 就用 v1.0 的形式 于是想办法将之前的分支名v1.0 修改为v1.0.0 注意思路是 先在本地修改好然后删除远程v1.0 tag和v1.0 branch然后重新推送 一些命令参考的这篇博客 先重命名本地分支 虽然不需要改但是这很重要不然下面的操作没法子做 git branch -m 旧分支名称 新分支名称 git branch -m v1.0 v2.0可以 git branch 查看一下 再重命名本地tag git tag 新tag名称 旧tag名称 git tag v1.0.0 v1.0可以 git tag 查看本地tag 好像并不是重命名而是复制了一份 那么正好将原来的v1.0 tag 直接删除了呗 删除旧tag git tag -d 标签名 git tag -d v1.0将本地重命名后的tag v1.0.0 推送到远程 git push origin v1.0.0到远程看有两个tag了内容完全一样删除旧的v1.0 删除后如下 再将本地branch名称修改过来 git branch -m 旧分支名称 新分支名称 git branch -m v2.0 v1.0现在本地已经修改完毕了 随便修改一个本地文件然后commit and push 就不会报错了 远程查看 注意切换到v1.0分支下查看 7). 推送分支代码到远程 1.2 环境准备 注意都是在v1.0分支下开发的 1). 在项目的pom.xml文件中导入spring data redis的maven坐标 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId /dependency2). 在项目的application.yml中加入redis相关配置 redis:host: 192.168.141.100port: 6379#password: root123456password: 123456database: 0注意: 引入上述依赖时,需要注意yml文件前面的缩进,上述配置应该配置在spring层级下面。 ip地址换成自己的这里我选择连接远程虚拟机的redis 3). 编写Redis的配置类RedisConfig,定义RedisTemplate 自己创建一个RedisTemplate对象放到IOC容器中或者说bean中这样boot自动装配发现ioc中已经有该类型的bean了就不会再帮你创建了直接注入 . 自己创建的好处,可以设置序列化器默认的序列化器不匹配有点麻烦 cn.whu.reggie.config.RedisConfig package cn.whu.reggie.config;import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer;Configuration public class RedisConfig extends CachingConfigurerSupport {Beanpublic RedisTemplateObject, Object redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplateObject, Object redisTemplate new RedisTemplate();//默认的Key序列化器为JdkSerializationRedisSerializerredisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setConnectionFactory(connectionFactory);return redisTemplate;} }解释说明: 1). 在SpringBoot工程启动时, 会加载一个自动配置类 RedisAutoConfiguration, 在里面已经声明了RedisTemplate这个bean 上述框架默认声明的RedisTemplate用的key和value的序列化方式是默认的 JdkSerializationRedisSerializer如果key采用这种方式序列化最终我们在测试时通过redis的图形化界面查询不是很方便如下形式 2). 如果使用我们自定义的RedisTemplate, key的序列化方式使用的是StringRedisSerializer, 也就是字符串形式, 最终效果如下: 3). 定义了两个bean会不会出现冲突呢? 答案是不会, 因为源码如下: 4). 提交到远程仓库一次 2. 缓存短信验证码 2.1 思路分析 前面我们已经实现了移动端手机验证码登录随机生成的验证码我们是保存在HttpSession中的。但是在我们实际的业务场景中一般验证码都是需要设置过期时间的如果存在HttpSession中就无法设置过期时间此时我们就需要对这一块的功能进行优化。 现在需要改造为将验证码缓存在Redis中具体的实现思路如下 1). 在服务端UserController中注入RedisTemplate对象用于操作Redis; 2). 在服务端UserController的sendMsg方法中将随机生成的验证码缓存到Redis中并设置有效期为5分钟; 3). 在服务端UserController的login方法中从Redis中获取缓存的验证码如果登录成功则删除Redis中的验证码; 2.2 代码改造 1). 在UserController中注入RedisTemplate对象用于操作Redis Autowired private RedisTemplate redisTemplate;2). 在UserController的sendMsg方法中将生成的验证码保存到Redis // 改用 redis 4、5两步合为一步了 【redis确实可以看成一种更快的session这么理解舒服多了啊】 // 将生成的验证码缓存到Redis中并且设置有效期5分钟 // key还是手机号 value还是code redisTemplate.opsForValue().set(phone,code,5, TimeUnit.MINUTES);4、5两步注释掉了 // 4. 将生成的验证码保存到Session session.setAttribute(phone,code); // 直接手机号phone作为key, 验证码code作为值// 5. 设置session失效时间为5min 注意单位为秒 SMSUtils.deadTime(5*60,phone,session);原来是工具类实现的5min过期开新线程用于销毁验证码现在也不需要了用redis可快多了 3). 在UserController的login方法中从Redis中获取生成的验证码如果登录成功则删除Redis中缓存的验证码 // 改用redis // 从redis中获取缓存的验证码 String redisCode (String) redisTemplate.opsForValue().get(phone);// 如果用户登录成功删除redis中缓存的验证码 redisTemplate.delete(phone);2.3 功能测试 代码编写完毕之后,重启服务。 1). 访问前端工程获取验证码 不要着急登录可以到RedisDesktopManager可视化工具里看看值 通过控制台的日志我们可以看到生成的验证码 2). 通过Redis的图形化界面工具查看Redis中的数据 先别点登录登录成功验证码就会被删除可视化工具里就看不到了 3). 在登录界面填写验证码登录完成后,查看Redis中的数据是否删除 先确认登录成功: 再刷新redis查看 果然电话号码那项就没有了 3. 缓存菜品信息 3.1 实现思路 前面我们已经实现了移动端菜品查看功能对应的服务端方法为DishController的list方法此方法会根据前端提交的查询条件(categoryId)进行数据库查询操作。在高并发的情况下频繁查询数据库会导致系统性能下降服务端响应时间增长。现在需要对此方法进行缓存优化提高系统的性能。 那么,我们又需要思考一个问题, 具体缓存几份数据呢, 所有的菜品缓存一份 , 还是说需要缓存多份呢? 我们可以看一下我们之前做的移动端效果: 我们点击哪一个分类,展示的就是该分类下的菜品, 其他菜品无需展示。所以这里面我们在缓存时可以根据菜品的分类缓存多份数据页面在查询时点击的是哪个分类我们就查询该分类下的菜品缓存数据。 具体的实现思路如下 1). 改造DishController的list方法先从Redis中获取分类对应的菜品数据如果有则直接返回无需查询数据库;如果没有则查询数据库并将查询到的菜品数据存入Redis。 2). 改造DishController的save和update方法加入清理缓存的逻辑。(有更新就清理下对应的缓存下次再请求就会去数据库查喽然后再给他放入缓存) 注意 ​ 在使用缓存过程中要注意保证数据库中的数据和缓存中的数据一致如果数据库中的数据发生变化需要及时清理缓存数据。否则就会造成缓存数据与数据库数据不一致的情况。 3.2 代码改造 需要改造的代码为 DishController 3.2.1 查询菜品缓存 改造的方法redis的数据类型redis缓存的keyredis缓存的valueliststringdish_分类Id_状态 , 比如: dish_12323232323_1List 1). 在DishController中注入RedisTemplate Autowired private RedisTemplate redisTemplate;2). 在list方法中,查询数据库之前,先查询缓存, 缓存中有数据, 直接返回 // 0. 先从redis中获取缓存数据 ListDishDto dishDtos null; //动态构造key String key dish_ dish.getCategoryId() _ dish.getStatus();//dish_1397844391040167938_1 dishDtos (ListDishDto) redisTemplate.opsForValue().get(key); // 会自动反序列化 多好呀// 0.1 redis中存在该数据直接返回无需查询数据库 if(dishDtos ! null){return R.success(dishDtos); }3). 如果redis不存在查询数据库并将数据库查询结果缓存在redis并设置过期时间 // 0.2 如果不存在才需要查询数据库并将查询到的菜品数据缓存到redis中 redisTemplate.opsForValue().set(key,dishDtos,60, TimeUnit.MINUTES); // 1) value直接就是对象 会自动帮你序列化和反序列化(也是为啥pojo一定得实现Serializable接口) // 2) 缓存也设置过期时间60min也就是1h, 万一一直没人访问释放很正常节省内存嘛 (个人觉得每次有查询就延长一点时间最好)3.2.2 清理菜品缓存 为了保证数据库中的数据和缓存中的数据一致如果数据库中的数据发生变化需要及时清理缓存数据。所以我们需要在添加菜品、更新菜品时清空缓存数据。 1). 修改菜品,清空缓存 在修改菜品的方法updateById中当菜品数据更新完毕之后需要清空菜品的缓存。那么这里清理菜品缓存的方式存在两种 A. 清理所有分类下的菜品缓存 // 方法一简单粗暴 清理所有菜品缓存 【同时也感受到了redis命令设计得好 spring封装得也好】 SetString keys redisTemplate.keys(dish_*);// 直接可以匹配 redisTemplate.delete(keys);// 直接可以批量删除B. 清理当前添加菜品分类下的缓存 // 方法二清理某个分类下的缓存数据 [精细清理] String key dish_ dishDto.getCategoryId() _1; redisTemplate.delete(key);注意: 在这里我们推荐使用第一种方式进行清理这样逻辑更加严谨。 因为对于修改操作用户是可以修改菜品的分类的如果用户修改了菜品的分类那么原来分类下将少一个菜品新的分类下将多一个菜品这样的话两个分类下的菜品列表数据都发生了变化。 2). 保存菜品修改菜品删除菜品,清空缓存 具体使用哪种方式呢视情况而定eg 保存菜品推荐使用第二种清理的方式, 只清理当前菜品关联的分类下的菜品数据。 修改菜品推荐使用第一种清理的方式, 因为一次修改可能涉及多个分类只清理一个不够 (突然想念存储过程了唉可惜人家不是redis) 还有就是该请求也是修改但是没有上传categoryId信息如果临时去查会不会反而降低了效率呢不如直接就清空了。 修改菜品updateById // 方法一简单粗暴 清理所有菜品缓存 【同时也感受到了redis命令设计得好 spring封装得也好】 SetString keys redisTemplate.keys(dish_*);// 直接可以匹配 redisTemplate.delete(keys);保存菜品 save // 方法二清理某个分类下的缓存数据 [精细清理] String key dish_ dishDto.getCategoryId() _1; redisTemplate.delete(key);(批量)起售/停售 updateByIds // 根本就不知道 categoryId 去数据库一个个查 那么redis的意义就小了 直接清空菜品缓存吧 SetString keys redisTemplate.keys(dish_*);// 直接可以匹配 redisTemplate.delete(keys);(批量)删除商品deleteByIds // 根本就不知道 categoryId 去数据库一个个查 那么redis的意义就小了 直接清空菜品缓存吧 SetString keys redisTemplate.keys(dish_*);// 直接可以匹配 redisTemplate.delete(keys);3.3 功能测试 代码编写完毕之后,重新启动服务。 1). 访问移动端根据分类查询菜品列表然后再检查Redis的缓存数据是否可以正常缓存 我们也可以在服务端通过debug断点的形式一步一步的跟踪代码的执行。 2). 当我们在进行新增及修改菜品时, 查询Redis中的缓存数据, 是否被清除; 3.4 提交并推送代码 1). 提交并推送代码 在v1.0分支中, 将我们已经实现并且测试通过的使用redis缓存验证码和菜品信息的代码,提交并推送至Gitee 2). 合并代码到master分支 A. 将代码切换到master分支 切换完成之后可以偷偷看看DishController,看看代码什么样的发现确实是修改之前的前面的修改都没有 B. 将v1.0分支的代码合并到当前master分支 merge完毕这个时候又可以偷偷看看代码发现修改的那些缓存代码全部同步过来了 C. 将master分支合并后代码推送到Gitee 修改了哪些地方都给给你列出来了真好 D. 切换回v1.0分支继续开发优化功能 4. SpringCache 4.1 介绍 Spring Cache是一个框架实现了基于注解的缓存功能只需要简单地加一个注解就能实现缓存功能大大简化我们在业务中操作缓存的代码。 Spring Cache只是提供了一层抽象底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。CacheManager是Spring提供的各种缓存技术抽象接口。 针对不同的缓存技术需要实现不同的CacheManager CacheManager描述EhCacheCacheManager使用EhCache作为缓存技术GuavaCacheManager使用Google的GuavaCache作为缓存技术RedisCacheManager使用Redis作为缓存技术 4.2 注解 在SpringCache中提供了很多缓存操作的注解常见的是以下的几个 注解说明EnableCaching开启缓存注解功能Cacheable在方法执行前spring先查看缓存中是否有数据如果有数据则直接返回缓存数据若没有数据调用方法并将方法返回值放到缓存中CachePut将方法的返回值放到缓存中CacheEvict将一条或多条数据从缓存中删除 在spring boot项目中使用缓存技术只需在项目中导入相关缓存技术的依赖包并在启动类上使用EnableCaching开启缓存支持即可。 例如使用Redis作为缓存技术只需要导入Spring data Redis的maven坐标即可。 4.3 入门程序 接下来我们将通过一个入门案例来演示一下SpringCache的常见用法。 上面我们提到SpringCache可以集成不同的缓存技术如Redis、Ehcache甚至我们可以使用Map来缓存数据 接下来我们在演示的时候就先通过一个Map来缓存数据最后我们再换成Redis来缓存。 4.3.1 环境准备 1). 数据库准备 drop database if exists cache_demo;create database cache_demo;use cache_demo;create table user(id bigint primary key,name varchar(255),age int,address varchar(255) )insert into user values(1,张三,18,北京); insert into user values(2,李四,19,上海); insert into user values(3,王五,20,广州); insert into user values(4,赵六,21,武汉); insert into user values(5,田七,22,南京);select * from user;2). 导入基础工程 基础环境的代码在我们今天的资料中已经准备好了 大家只需要将这个工程导入进来就可以了。导入进来的工程结构如下 链接https://pan.baidu.com/s/174IEaLXYwzTJhEAl-RIj4Q 提取码nli8 就不自己慢慢创建了直接导入吧 由于SpringCache的基本功能是Spring核心(spring-context)中提供的所以目前我们进行简单的SpringCache测试是可以不用额外引入其他依赖的。 注意 application.yml 里的password改成自己的 3). 注入CacheManager 我们可以在UserController注入一个CacheManager在Debug时我们可以通过CacheManager跟踪缓存中数据的变化。 我们可以看到CacheManager是一个接口默认的实现有以下几种 而在上述的这几个实现中默认使用的是 ConcurrentMapCacheManager。稍后我们可以通过断点的形式跟踪缓存数据的变化。 4). 引导类上加EnableCaching 在引导类上加该注解就代表当前项目开启缓存注解功能。 4.3.2 CachePut注解 CachePut 说明 ​ 作用: 将方法返回值放入缓存 ​ value: 缓存的名称, 每个缓存名称下面可以有很多key ​ key: 缓存的key ---------- 支持Spring的表达式语言SPEL语法 1). 在save方法上加注解CachePut 当前UserController的save方法是用来保存用户信息的我们希望在该用户信息保存到数据库的同时也往缓存中缓存一份数据我们可以在save方法上加上注解 CachePut用法如下 /*** CachePut: 将方法返回值放入缓存* value: 缓存的名称每个缓存名称下面可以有多个key (userCache表示user模块这一大类的缓存)* key: 缓存的key* * (可以通过spel(spring表达式语言)获取方法内的变量)* #result 就表示方法返回值 》 #result.id* #user 就获取了参数 (user是参数名) 》 #user.id*/ CachePut(value userCache,key #user.id) PostMapping public User save(User user){userService.save(user);return user; }key的写法如下 ​ #user.id : #user指的是方法形参的名称, id指的是user的id属性 , 也就是使用user的id属性作为key ; ​ #user.name: #user指的是方法形参的名称, name指的是user的name属性 ,也就是使用user的name属性作为key ; ​ ​ #result.id : #result代表方法返回值该表达式 代表以返回对象的id属性作为key ​ #result.name : #result代表方法返回值该表达式 代表以返回对象的name属性作为key 2). 测试 启动服务,通过postman请求访问UserController的方法, 然后通过断点的形式跟踪缓存数据。 第一次访问时缓存中的数据是空的因为save方法执行完毕后才会缓存数据。 第二次访问时我们通过debug可以看到已经有一条数据了就是上次保存的数据已经缓存了缓存的key就是用户的id。 注意: 上述的演示最终的数据实际上是缓存在ConcurrentHashMap中那么当我们的服务器重启之后缓存中的数据就会丢失。 我们后面使用了Redis来缓存就不存在这样的问题了。 4.3.3 CacheEvict注解 CacheEvict 说明 ​ 作用: 清理指定缓存 ​ value: 缓存的名称每个缓存名称下面可以有多个key ​ key: 缓存的key ---------- 支持Spring的表达式语言SPEL语法 1). 在 delete 方法上加注解CacheEvict 当我们在删除数据库user表的数据的时候,我们需要删除缓存中对应的数据,此时就可以使用CacheEvict注解, 具体的使用方式如下: /** * CacheEvict清理指定缓存 * value缓存的名称每个缓存名称下面可以有多个key * key缓存的key */ CacheEvict(value userCache,key #p0) //#p0 代表第一个参数 //CacheEvict(value userCache,key #root.args[0]) //#root.args[0] 代表第一个参数 //CacheEvict(value userCache,key #id) //#id 代表变量名为id的参数 DeleteMapping(/{id}) public void delete(PathVariable Long id){userService.removeById(id); }2). 测试 要测试缓存的删除我们先访问save方法4次保存4条数据到数据库的同时也保存到缓存中最终我们可以通过debug看到缓存中的数据信息。 然后我们在通过postman访问delete方法 如下 略 删除数据时通过debug我们可以看到已经缓存的4条数据 略 当执行完delete操作之后我们再次保存一条数据在保存的时候debug查看一下删除的ID值是否已经被删除。 略 发现此处使用Map作为缓存虽然也都是缓存在内存但是不能称之为数据库因为项目一重启map缓存会随着全部丢失。 而redis其实和项目本身是分开的虽然也是存在内存中但是项目进程被干掉redis还在运行哪些redis内存缓存还会存在下次项目重启还能不丢失继续使用。这也是为啥redis将数据存储在内存还敢号称数据的原因真的做到了把内存当做硬盘用。 3). 在 update 方法上加注解CacheEvict 在更新数据之后数据库的数据已经发生了变更我们需要将缓存中对应的数据删除掉避免出现数据库数据与缓存数据不一致的情况。 // 此处这4种写法都是等价的 //CacheEvict(value userCache,key #p0.id) //第一个参数的id属性 //CacheEvict(value userCache,key #root.args[0].id) //第一个参数的id属性 //CacheEvict(value userCache,key #result.id) //返回值的id属性 CacheEvict(value userCache,key #user.id) //参数名为user参数的id属性 PutMapping public User update(User user){userService.updateById(user);return user; }加上注解之后我们可以重启服务然后测试方式基本和上述相同先缓存数据然后再更新某一条数据通过debug的形式查询缓存数据的情况。 4.3.4 Cacheable注解 Cacheable 说明: ​ 作用: 在方法执行前spring先查看缓存中是否有数据如果有数据则直接返回缓存数据若没有数据调用方法并将方法返回值放到缓存中 ​ value: 缓存的名称每个缓存名称下面可以有多个key ​ key: 缓存的key ---------- 支持Spring的表达式语言SPEL语法 1). 在getById上加注解Cacheable /*** Cacheable在方法执行前spring先查看缓存中是否有数据如果有数据则直接返回缓存数据若没有数据调用方法并将方法返回值放到缓存中* value缓存的名称每个缓存名称下面可以有多个key* key缓存的key*/ Cacheable(value userCache, key #id) GetMapping(/{id}) public User getById(PathVariable Long id){User user userService.getById(id);return user; }2). 测试 我们可以重启服务然后通过debug断点跟踪程序执行。我们发现第一次访问会请求我们controller的方法查询数据库。后面再查询相同的id就直接获取到数据库不用再查询数据库了就说明缓存生效了。 图略 problem: 当我们在测试时查询一个数据库不存在的id值第一次查询缓存中没有也会查询数据库。而第二次再查询时会发现不再查询数据库了而是直接返回那也就是说如果根据ID没有查询到数据,那么会自动缓存一个null值。 我们可以通过debug验证一下 我们能不能做到当查询到的值不为null时再进行缓存如果为null则不缓存呢? 答案是可以的。 3). 缓存非null值 在Cacheable注解中提供了两个属性分别为 condition unless 。 condition : 表示满足什么条件, 再进行缓存 ; unless : 表示满足条件则不缓存 ; 与上述的condition是反向的 ; 具体实现方式如下: /*** Cacheable在方法执行前spring先查看缓存中是否有数据如果有数据则直接返回缓存数据若没有数据调用方法并将方法返回值放到缓存中* value缓存的名称每个缓存名称下面可以有多个key* key缓存的key** condition条件满足条件时才缓存数据 无法获取result * unless满足条件则不缓存*/ Cacheable(value userCache, key #id, unless #result null) GetMapping(/{id}) public User getById(PathVariable Long id){User user userService.getById(id);return user; }注意 此处我们使用的时候只能够使用 unless 因为在condition中我们是无法获取到结果 #result的。 4). 在list方法上加注解Cacheable 在list方法中进行查询时有两个查询条件如果传递了id根据id查询 如果传递了name 根据name查询那么我们缓存的key在设计的时候就需要既包含id又包含name。 具体的代码实现如下 Cacheable注解不仅可以读缓存还可以写缓存 全能啊 // 这个注解不仅可以读缓存还可以自己写缓存 ★ // 查询条件有2个所以key也关联2个 Cacheable(value userCache,key #user.id _ #user.name) GetMapping(/list) public ListUser list(User user){LambdaQueryWrapperUser queryWrapper new LambdaQueryWrapper();queryWrapper.eq(user.getId() ! null,User::getId,user.getId());queryWrapper.eq(user.getName() ! null,User::getName,user.getName());ListUser list userService.list(queryWrapper);return list; }然后再次重启服务进行测试。 第一次查询时需要查询数据库在后续的查询中就直接查询了缓存不再查询数据库了。 4.4 集成Redis 在使用上述默认的ConcurrentHashMap做缓存时服务重启之后之前缓存的数据就全部丢失了操作起来并不友好。在项目中使用我们会选择使用redis来做缓存主要需要操作以下几步 1). pom.xml dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-cache/artifactId /dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId /dependency2). application.yml spring:redis:host: 192.168.200.200port: 6379password: root123456database: 0cache:redis:time-to-live: 1800000 #设置缓存过期时间可选 (单位ms: 1800000ms1800s30min)加上redis依赖并且yml中配置上redis顶层CacheManager接口就会自动使用redis的实现类也就是底层使用redis缓存而非map缓存 3). 测试 重新启动项目通过postman发送根据id查询数据的请求然后通过redis的图形化界面工具查看redis中是否可以正常的缓存数据。 确实就用到redis啦~ 重启服务器再次访问相同的链接发现缓存还在~ 5. 缓存套餐数据 5.1 实现思路 前面我们已经实现了移动端套餐查看功能对应的服务端方法为SetmealController的list方法此方法会根据前端提交的查询条件进行数据库查询操作。在高并发的情况下频繁查询数据库会导致系统性能下降服务端响应时间增长。现在需要对此方法进行缓存优化提高系统的性能。 具体的实现思路如下 1). 导入Spring Cache和Redis相关maven坐标 2). 在application.yml中配置缓存数据的过期时间 3). 在启动类上加入EnableCaching注解开启缓存注解功能 4). 在SetmealController的list方法上加入Cacheable注解 (写缓存读缓存) 5). 在SetmealController的save和delete方法上加入CacheEvict注解 5.2 缓存套餐数据 5.2.1 代码实现 1). pom.xml中引入依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-cache/artifactId /dependency备注: spring-boot-starter-data-redis 这个依赖前面已经引入了, 无需再次引入。 2). application.yml中设置缓存过期时间 spring: cache:redis:time-to-live: 1800000 #设置缓存数据的过期时间3). 启动类上加入EnableCaching注解 4). SetmealController的list方法上加入Cacheable注解 在进行套餐数据查询时我们需要根据分类ID和套餐的状态进行查询所以我们在缓存数据时可以将套餐分类ID和套餐状态组合起来作为key如 1627182182_1 (1627182182为分类ID1为状态)。 /** * 根据条件查询套餐数据 * param setmeal * return */ GetMapping(/list) Cacheable(value setmealCache,key #setmeal.categoryId _ #setmeal.status) public RListSetmeal list(Setmeal setmeal){LambdaQueryWrapperSetmeal queryWrapper new LambdaQueryWrapper();queryWrapper.eq(setmeal.getCategoryId() ! null,Setmeal::getCategoryId,setmeal.getCategoryId());queryWrapper.eq(setmeal.getStatus() ! null,Setmeal::getStatus,setmeal.getStatus());queryWrapper.orderByDesc(Setmeal::getUpdateTime);ListSetmeal list setmealService.list(queryWrapper);return R.success(list); }5.2.2 测试 缓存数据的代码编写完毕之后重新启动服务访问移动端进行测试我们登陆之后在点餐界面点击某一个套餐分类查询套餐列表数据时服务端报错了错误信息如下 为什么会报出这个错误呢 因为 Cacheable 会将方法的返回值R缓存在Redis中而在Redis中存储对象该对象是需要被序列化的而对象要想被成功的序列化就必须得实现 Serializable 接口。而当前我们定义的R并未实现 Serializable 接口。所以要解决该异常只需要让R实现 Serializable 接口即可。如下 修复完毕之后再次重新测试访问套餐分类下对应的套餐列表数据后我们会看到Redis中确实可以缓存对应的套餐列表数据。 5.3 清理套餐数据 5.3.1 代码实现 为了保证数据库中数据与缓存数据的一致性在我们添加套餐或者删除套餐数据之后需要清空当前套餐缓存的全部数据。那么CacheEvict注解如何清除某一份缓存下所有的数据呢这里我们可以指定CacheEvict中的一个属性 allEnties将其设置为true即可。 1). 在delete方法上加注解CacheEvict DeleteMapping CacheEvict(value setmealCache,allEntries true) // allEntries true 表示清理所有缓存 public RString delete(RequestParam ListLong ids){log.info(根据id批量删除(单个id就是单删): ids{},ids);setmealService.removeWithDish(ids);//删除套餐,还要删除中间表setmeal_dish的套餐-菜品关联记录return R.success(删除成功!); }2). 在save方法上加注解CacheEvict PostMapping CacheEvict(value setmealCache,allEntries true) // allEntries true 表示清理所有缓存 public RString save(RequestBody SetmealDto setmealDto){log.info(套餐信息{},setmealDto);setmealService.saveWithDish(setmealDto);return R.success(新增套餐成功); }5.3.2 测试 代码编写完成之后,重启工程,然后访问后台管理系统,对套餐数据进行新增 以及 删除, 然后通过Redis的图形化界面工具,查看Redis中的套餐缓存是否已经被删除。 果然被删除了 5.3.3 其他功能缓存处理 其实只有前台查询需要缓存处理因为前台访问量是巨大的后台访问量很小不需要缓存也没事儿。 但是对于一些更新操作必须得有清空缓存操作不然业务逻辑就不对了。 所以修改套餐信息和批量启售/停售 controller方法上得加上清空缓存的操作 CacheEvict(value setmealCache,allEntries true)(也要清空万一修改了套餐类型呢) 5.4 提交推送代码 到目前为止我们已经在v1.0这个分支中完成了套餐数据的缓存接下来我们就需要将代码提交并推送到远程仓库。 然后在idea中切换到master分支然后将v1.0分支的代码合并到master。 再将合并后的master分支的代码推送到远程仓库。 查看下远程仓库是否真的推送到了
文章转载自:
http://www.morning.wdhzk.cn.gov.cn.wdhzk.cn
http://www.morning.dkzrs.cn.gov.cn.dkzrs.cn
http://www.morning.myrmm.cn.gov.cn.myrmm.cn
http://www.morning.cprbp.cn.gov.cn.cprbp.cn
http://www.morning.cryb.cn.gov.cn.cryb.cn
http://www.morning.xdlwm.cn.gov.cn.xdlwm.cn
http://www.morning.bnfjh.cn.gov.cn.bnfjh.cn
http://www.morning.cwrnr.cn.gov.cn.cwrnr.cn
http://www.morning.hwycs.cn.gov.cn.hwycs.cn
http://www.morning.hzryl.cn.gov.cn.hzryl.cn
http://www.morning.bwdnx.cn.gov.cn.bwdnx.cn
http://www.morning.swkzk.cn.gov.cn.swkzk.cn
http://www.morning.prhqn.cn.gov.cn.prhqn.cn
http://www.morning.gbtty.cn.gov.cn.gbtty.cn
http://www.morning.rntyn.cn.gov.cn.rntyn.cn
http://www.morning.yfnjk.cn.gov.cn.yfnjk.cn
http://www.morning.xmttd.cn.gov.cn.xmttd.cn
http://www.morning.ishoufeipin.cn.gov.cn.ishoufeipin.cn
http://www.morning.tqsnd.cn.gov.cn.tqsnd.cn
http://www.morning.yqwsd.cn.gov.cn.yqwsd.cn
http://www.morning.mszwg.cn.gov.cn.mszwg.cn
http://www.morning.srndk.cn.gov.cn.srndk.cn
http://www.morning.rjbb.cn.gov.cn.rjbb.cn
http://www.morning.qsszq.cn.gov.cn.qsszq.cn
http://www.morning.fgxws.cn.gov.cn.fgxws.cn
http://www.morning.cgntj.cn.gov.cn.cgntj.cn
http://www.morning.kwblwbl.cn.gov.cn.kwblwbl.cn
http://www.morning.tkzqw.cn.gov.cn.tkzqw.cn
http://www.morning.lcwhn.cn.gov.cn.lcwhn.cn
http://www.morning.tdwjj.cn.gov.cn.tdwjj.cn
http://www.morning.mlnbd.cn.gov.cn.mlnbd.cn
http://www.morning.bfrff.cn.gov.cn.bfrff.cn
http://www.morning.zsgbt.cn.gov.cn.zsgbt.cn
http://www.morning.gcspr.cn.gov.cn.gcspr.cn
http://www.morning.xpgwz.cn.gov.cn.xpgwz.cn
http://www.morning.bxrlt.cn.gov.cn.bxrlt.cn
http://www.morning.jltmb.cn.gov.cn.jltmb.cn
http://www.morning.cjmmt.cn.gov.cn.cjmmt.cn
http://www.morning.gfqj.cn.gov.cn.gfqj.cn
http://www.morning.xqjrg.cn.gov.cn.xqjrg.cn
http://www.morning.wnqfz.cn.gov.cn.wnqfz.cn
http://www.morning.mdgpp.cn.gov.cn.mdgpp.cn
http://www.morning.xscpq.cn.gov.cn.xscpq.cn
http://www.morning.ssglh.cn.gov.cn.ssglh.cn
http://www.morning.csnch.cn.gov.cn.csnch.cn
http://www.morning.qwmsq.cn.gov.cn.qwmsq.cn
http://www.morning.nbqwt.cn.gov.cn.nbqwt.cn
http://www.morning.yggwn.cn.gov.cn.yggwn.cn
http://www.morning.pbmkh.cn.gov.cn.pbmkh.cn
http://www.morning.cwjxg.cn.gov.cn.cwjxg.cn
http://www.morning.pfntr.cn.gov.cn.pfntr.cn
http://www.morning.nqwz.cn.gov.cn.nqwz.cn
http://www.morning.smzr.cn.gov.cn.smzr.cn
http://www.morning.jfxth.cn.gov.cn.jfxth.cn
http://www.morning.nkyc.cn.gov.cn.nkyc.cn
http://www.morning.dxrbp.cn.gov.cn.dxrbp.cn
http://www.morning.lcbt.cn.gov.cn.lcbt.cn
http://www.morning.tytly.cn.gov.cn.tytly.cn
http://www.morning.tkryt.cn.gov.cn.tkryt.cn
http://www.morning.qscsy.cn.gov.cn.qscsy.cn
http://www.morning.wmhlz.cn.gov.cn.wmhlz.cn
http://www.morning.madamli.com.gov.cn.madamli.com
http://www.morning.rqfzp.cn.gov.cn.rqfzp.cn
http://www.morning.nwljj.cn.gov.cn.nwljj.cn
http://www.morning.yrxcn.cn.gov.cn.yrxcn.cn
http://www.morning.rrxmm.cn.gov.cn.rrxmm.cn
http://www.morning.dtnjr.cn.gov.cn.dtnjr.cn
http://www.morning.txlxr.cn.gov.cn.txlxr.cn
http://www.morning.ryjl.cn.gov.cn.ryjl.cn
http://www.morning.yrdkl.cn.gov.cn.yrdkl.cn
http://www.morning.bkxnp.cn.gov.cn.bkxnp.cn
http://www.morning.mjqms.cn.gov.cn.mjqms.cn
http://www.morning.lwrcg.cn.gov.cn.lwrcg.cn
http://www.morning.dkcpt.cn.gov.cn.dkcpt.cn
http://www.morning.kqhlm.cn.gov.cn.kqhlm.cn
http://www.morning.rgrys.cn.gov.cn.rgrys.cn
http://www.morning.pfcrq.cn.gov.cn.pfcrq.cn
http://www.morning.kjyfq.cn.gov.cn.kjyfq.cn
http://www.morning.xfhms.cn.gov.cn.xfhms.cn
http://www.morning.hkchp.cn.gov.cn.hkchp.cn
http://www.tj-hxxt.cn/news/246317.html

相关文章:

  • 电子商务网站建设 教案做网站大型
  • 中国著名的个人网站网站注册哪个好
  • 国企网站建设方案网站有免费的域名和空间么
  • 个人备案网站 内容wordpress游戏支付
  • 网网站制作更换网站服务商 重新制作了网站
  • 网站设计和内容上的不足和建议在演示文稿上网站怎么做
  • 太原网站优化公司泉州自助建站软件
  • 织梦网站首页文章美食的网站建设个人总结
  • 如何做一个网站代码全部游戏免费(试玩)
  • 重庆网站备案在那里营销手机都有什么功能啊
  • 手机建网站花钱吗什么是网络营销?有何特点
  • 网站建设 数据可视化站长之家seo
  • 重庆北京网站建设后端开发工程师
  • 金光华网站建设如何做外贸营销型网站推广
  • 购物网站怎么做SEOip切换工具
  • 网站备案变更主体学校二级学院网站建设
  • php网站如何编辑wordpress电子书模板
  • 建设部网站刘赵云网站如何做微信支付宝支付宝支付
  • wordpress主题摘要字数seo分析
  • 呼和浩特网站建设宣传北京网站开发哪家好
  • 网站服务内容怎样选怎么做网页机器人
  • 工信部网站 验证码漫画网站模板
  • 上城区建设局网站龙华建设网站公司
  • 免费行情网站大全市场推广渠道有哪些
  • 考证培训机构报名网站建设部网站材料价格上涨规定
  • 找谁做网站比较好做资源网站 文件能存储到云盘吗
  • 哪些网站平台可以做推广昆明开发
  • 提供做网站企业阿里云4核8g云服务器多少钱
  • 如何构建一个电子商务网站凯里网络公司建设网站
  • 上饶市建设培训中心网站seo诊断网站