网站栏目管理软件培训招生
- 作者: 五速梦信息网
- 时间: 2026年03月21日 07:33
当前位置: 首页 > news >正文
网站栏目管理,软件培训招生,事业单位的网站建设费列哪,小红书达人kol推广【云岚到家】-day03-门户缓存方案选择 1.门户常用的技术方案 什么是门户 说到门户马上会想到门户网站#xff0c;中国比较早的门户网站有新浪、网易、搜狐、腾讯等#xff0c;门户网站为用户提供一个集中的、易于访问的平台#xff0c;使他们能够方便地获取各种信息和服务…【云岚到家】-day03-门户缓存方案选择 1.门户常用的技术方案 什么是门户 说到门户马上会想到门户网站中国比较早的门户网站有新浪、网易、搜狐、腾讯等门户网站为用户提供一个集中的、易于访问的平台使他们能够方便地获取各种信息和服务 这里我们说的门户是指一个网站或应用程序的主页它是用户进入这个网站或系统的入口主页上通常聚合很多的信息包括内容导航、热点信息等比如门户网站的首页、新闻网站的首页、小程序的首页等 1.1 常用的技术方案 基于两个需求去分析 1.门户上的信息是动态的门户上的信息会按照一定的时间周期去更新比如一个新闻网站不可能一直显示一样的新闻 2.门户作为入口其访问频率非常高对于访问频率高的界面其加载速度是至关重要的因为它直接影响用户的体验和留存率。一般来说门户网站的首页应该在2至3秒内加载完成这被认为是一个合理的加载时间目标 常见的两类门户是web门户和移动应用门户 1.1.1 Web门户 web门户是最常见的门户类型比如新浪、百度新闻等它们通过PC浏览器访问用户可以通过桌面电脑、笔记本电脑、平板电脑和智能手机等设备访问。Web门户通常运行在Web浏览器上用户可以通过输入网址或通过搜索引擎访问 web门户是通过浏览器访问html网页虽然html网页上的内容是动态的但是考虑门户作为入口其访问频率非常高所以就需要提高它的加载速度如果网页上的数据是通过实时查询数据库得到是无法满足要求的所以针对web门户提高性能的关键是如何提高html文件的访问性能如何提高查询数据的性能 1.将门户页面生成静态网页发布到CDN服务器 纯静态网页通过Nginx加载要比去Tomcat加载快很多。 我们可以使用模板引擎技术将动态数据静态化生成html文件并通过CDN分发到边缘服务器可以提高访问效率。 Java模板引擎技术有很多比如freemarker、velocity等 什么是CDN CDN 是构建在数据网络上的一种分布式的内容分发网旨在提高用户访问网站或应用时的性能(存放静态资源)通过CDN将内容分发到各个城市的CDN节点上北京的网民请求北京的服务即可拿到资源提高访问速度 2.html文件上的静态资源比如图片、视频、CSS、Js等也全部放到CDN服务 3.html上的动态数据更新频率高的通过异步请求后端缓存服务器加载不要直接查询数据库通过Redis缓存提高查询速度 4.使用负载均衡通过部署多个Nginx服务器共同提供服务不仅保证系统的可用性还可以提高系统的访问性能(三个人同时干活一个出了问题还有另外两个) 5.在前端也做一部分缓存 不仅服务端可以做缓存前端也可以做缓存前端可以把缓存信息存储到 LocalStorage 提供了持久化存储可以存储大量数据 SessionStorage 与 LocalStorage 类似但数据只在当前会话中有效当用户关闭标签页或浏览器时清空 Cookie: 存储在用户计算机上的小型文本文件可以在客户端和服务器之间传递数据 浏览器缓存通过 HTTP 头部控制比如Cache-Control头部提供了更灵活的缓存控制选项可以定义缓存的最大有效时间 1.1.2 移动应用门户 移动应用门户是专为移动设备如智能手机和平板电脑设计的应用程序比如小程序、APP等用户可以通过应用商店下载并安装。这些应用程序提供了更好的用户体验通常具有更高的性能和交互性可以直接从设备主屏幕启动 对于移动应用提高访问效率方法通常有 静态资源要走CDN服务器 对所有请求进行负载均衡 在前端及服务端缓存门户上显示的动态数据 根据上边的分析对于Java程序员需要关注的是缓存服务的开发主流的缓存服务器是Redis所以我们接下来的工作重点是使用Redis为门户开发缓存服务接口 1.2 缓存技术方案 1.2.1 需求分析 目标明确本项目门户有哪些信息需要缓存 1.界面原型 了解了门户的技术方案下边通过门户界面原型分析本项目门户包括哪些部分本项目小程序门户首页如下图 2.缓存需求 根据门户的技术方案为了提供效率门户显示的信息从缓存查询根据上边的界面原型分析有哪些信息需要缓存 1.定位界面上的已开通区域列表 2.服务搜索 通过Elasticsearch查询es自带缓存 3.首页服务列表 4.热门服务列表 5.服务信息 点击某一个服务打开服务详情页面如下图 服务的详细信息一部分是服务介绍的图片和内容等一部分是区域服务信息比如价格 6.服务分类 在全部服务界面左侧显示服务分类服务分类下的服务项通过Elasticsearch去查询 小结 1.首页服务列表包括两个服务分类及每个分类下的四个服务项 2.热门服务列表 3.服务类型列表 4.开通城市列表 5.服务详细信息内容包括服务项信息、服务信息 1.3 Spring Cache入门 1.3.1 入门程序 目标学会使用SpringCache查询缓存注解并理解它的原理 Redis访问工具 面试官你们项目中用的redis客户端是什么缓存用的什么框架 本项目使用Redis存储缓存数据如何通过Java去访问Redis 常用的有Jedis和Lettuce两个访问redis的客户端库其中Lettuce的性能和并发性要好一些SpringBoot 默认使用的是 Lettuce 作为 Redis 的客户端 本项目集成了Spring data redis框架在项目中可以通过RedisTemplate访问RedisRedisTemplate提供了方便访问redis的模板方法 RedisTemplate和Lettuce 是什么关系 RedisTemplate进行 Redis 操作时实际上是通过 Lettuce客户端与 Redis 服务器进行通信 本项目也集成了Spring CacheSpring Cache是spring的缓存框架可以集成各种缓存中间件比如EhCache(缓存服务)、Caffeine(缓存服务)、redis Spring Cache最终也是通过Lettuce 去访问redis 使用Spring Cache的方法很简单只需要在方法上添加注解即可实现将方法返回数据存入缓存以及清理缓存等注解的使用 RedisTemplate适用于灵活操作redis的场景通过RedisTemplate的API灵活访问Redis 面试官你们项目使用redis用的什么框架 Spring Cache、spring data redisRedisTemplate调用方法 Spring Cache基本介绍 Spring Cache是Spring提供的一个缓存框架基于AOP原理实现了基于注解的缓存功能只需要简单地加一个注解就能实现缓存功能对业务代码的侵入性很小 基于SpringBoot使用Spring Cache非常简单首先加入依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-cache/artifactIdversion2.7.10/version /dependency本项目在jzo2o-framework下的jzo2o-redis工程引入此依赖其它服务只需要引入jzo2o-redis的依赖即可 简单认识它的常用注解 EnableCaching开启缓存注解功能启动类上使用 Cacheable查询数据时缓存将方法的返回值进行缓存 CacheEvict用于删除缓存将一条或多条数据从缓存中删除 CachePut用于更新缓存将方法的返回值放到缓存中 Caching组合多个缓存注解 CacheConfig统一配置Cacheable中的value值 搭建环境 在jzo2o-foundations工程创建新分支dev_02并切换到该分支在jzo2o-foundations工程引入jzo2o-redis依赖 dependencygroupIdcom.jzo2o/groupIdartifactIdjzo2o-redis/artifactId /dependency在jzo2o-foundations工程的bootstrap.yml中引入redis的配置文件如下图 在nacos配置shared-redis-cluster.yaml开发环境使用redis单机注意配置redis的IP地址、端口和密码 4.查询数据时缓存 下边使用Cacheable注解实现查询服务信息时对服务信息进行缓存它的执行流程是第一次查询服务信息缓存中没有该服务的信息此时去查询数据库查询数据库拿到服务信息并进行缓存第二次再去查询该服务信息发现缓存中有该服务的信息则直接查询缓存不再去数据库查询 流程如下重要 首先在工程启动类中添加EnableCaching注解它表示开启Spring cache缓存组件 下边实现对区域服务信息查询时进行缓存。 首先找到区域服务信息的service为了不和原来的getById(Serializable id)查询方法混淆单独定义查询区域服务信息缓存的方法如下 在IServeService接口中定义如下接口 public interface IServeService extends IServiceServe {/*** 查询区域服务信息并进行缓存* param id 对应serve表的主键* return 区域服务信息/Serve queryServeByIdCache(Long id); }在接口实现类中定义如下方法此时该方法还是查询数据库 Service public class ServeServiceImpl extends ServiceImplServeMapper, Serve implements IServeService {Overridepublic Serve queryServeByIdCache(Long id) {Serve serve baseMapper.selectById(id);return serve;} }下边在方法中添加Cacheable注解 Service public class ServeServiceImpl extends ServiceImplServeMapper, Serve implements IServeService {//Cacheable(value JZ_CACHE:SERVE_RECORD,key #id)Cacheable(value RedisConstants.CacheName.SERVE,key #id)//缓存到redis,常量就是JZ_CACHE:SERVE_RECORDOverridepublic Serve queryServeByIdCache(Long id) {Serve serve baseMapper.selectById(id);return serve;} }Cacheable注解配置的两项参数说明 value缓存的名称缓存名称作为缓存key的前缀 key: 缓存key支持SpEL表达式上述代码表示取参数id的值作为key最终缓存key为缓存名称“::”key例如上述代码id为123,最终的key为JZ_CACHE:SERVE_RECORD::123 SpEL是一种在 Spring 框架中用于处理字符串表达式的强大工具它可以实现获取对象的属性调用对象的方法操作 keyGenerator指定一个自定义的键生成器实现 org.springframework.cache.interceptor.KeyGenerator 接口的类用于生成缓存的键。与 key 属性互斥二者只能选其一 测试 对queryServeByIdCache方法进行测试编写单元测试方法 SpringBootTest Slf4j class IServeServiceTest {Resourceprivate IServeService serveService;//区域服务查询Testpublic void test_queryServeByIdCache(){Serve serve serveService.queryServeByIdCache(1693815623867506689L);Assert.notNull(serve,服务为空);} }运行测试方法观察redis数据缓存成功 缓存keyJZ_CACHE:SERVE_RECORD::1693815623867506689 缓存valueserve表的记录 TTL缓存过期时间-1表示永不过期 调整缓存过期时间 虽然数据被成功缓存如果想调整缓存过期时间怎么做呢 在Cacheable注解中有一个属性为cacheManager表示缓存管理器通过缓存管理器可以设置缓存过期时间。 所有缓存相关的基础类都在jzo2o-redis工程在jzo2o-redis工程定义spring cache需要的缓存管理器 上图中共包括三个缓存管理器 缓存时间为30分钟、一天、永久分别对应的bean的名称为cacheManager30Minutes、cacheManagerOneDay、cacheManagerForever 下边我们在Cacheable注解中指定缓存管理器为cacheManagerOneDay即缓存时间为一天 Cacheable(value RedisConstants.CacheName.SERVE,key#id,cacheManager RedisConstants.CacheManager.ONE_DAY) public Serve queryServeByIdCache(Long id) {Serve serve baseMapper.selectById(id);return serve; }重新运行单元测试方法我们发现缓存的过期时间没有改变这是为什么 原因是根据前边的缓存流程先查询缓存如果缓存存在则直接查询缓存返回数据不再向缓存存储数据 所以我们需要删除缓存重新运行测试方法测试通过观察redis中的缓存过期时间已经改变这说明我们设置的缓存管理器生效 由于缓存时间加了随机数缓存一天的时间为90000秒左右 工作原理 Spring Cache是基于AOP原理对添加注解Cacheable的类生成代理对象在方法执行前查看是否有缓存对应的数据如果有直接返回数据如果没有调用源方法获取数据返回并缓存起来下边跟踪Spring Cache的切面类CacheAspectSupport.java中的private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts)方法 下边打断点调试 分别测试命中缓存和未命中缓存的情况第一次查询redis中没有缓存时执行方法查询数据库第二次命中缓存直接查询redis不再执行方法 测试Spring Cache 目标学会使用CacheEvict和CachePut注解 在Spring Cache入门中使用了Cacheable 注解它实现的是查询时进行缓存 下边测试另外两个常用的注解如下 CacheEvict用于删除缓存将一条或多条数据从缓存中删除 CachePut用于更新缓存将方法的返回值放到缓存中 测试CachePut CachePut注解实现的是将方法的返回值放到缓存中 在服务上架后会将区域服务的信息写入缓存服务下架会从缓存删除下边我们实现服务上架将服务写入缓存 找到服务上架的方法在方法上添加CachePut注解 Override Transactional CachePut(value RedisConstants.CacheName.SERVE, key #id, cacheManager RedisConstants.CacheManager.ONE_DAY) public Serve onSale(Long id){ …. }上边代码同样指定了缓存名称、缓存key及缓存管理器缓存过期时间为一天 测试CacheEvict 找到服务下架的方法添加CacheEvict注解 Override Transactional CacheEvict(value RedisConstants.CacheName.SERVE, key #id) public Serve offSale(Long id){ …. } 小结 Spring Cache有哪些常用的注解都有什么用 EnableCaching开启缓存注解功能 Cacheable查询数据时缓存将方法的返回值进行缓存 CacheEvict用于删除缓存将一条或多条数据从缓存中删除 CachePut用于更新缓存将方法的返回值放到缓存中 Caching组合多个缓存注解 1.4 缓存常见问题 1.4.1 缓存穿透问题 在使用缓存时特别是在高并发场景下会遇到很多问题常用的问题有缓存穿透、缓存击穿、缓存雪崩以及缓存一致性问题 1.什么是缓存穿透问题 缓存穿透是指请求(访问)一个不存在的数据缓存层和数据库层都没有这个数据这种请求会穿透缓存直接到数据库进行查询。它通常发生在一些恶意用户可能故意发起不存在的请求试图让系统陷入这种情况以耗尽数据库连接资源或者造成性能问题 比如在快速入门程序中查询一个缓存中不存在的数据将会执行方法查询数据库数据库也不存在此数据查询完数据库也没有缓存数据缓存没有起到作用 2.解决方案 1.对请求增加校验机制 比如查询的Id是长整型并且是19位如果发来的不是长整型或不符合位数则直接返回不再查询数据库 2.缓存空值或特殊值 当查询数据库得到的数据不存在此时我们仍然去缓存数据缓存一个空值或一个特殊值的数据避免每次都会查询数据库避免缓存穿透 3.使用布隆过滤器 什么是布隆过滤器 布隆过滤器是一种数据结构用于快速判断一个元素是否属于一个集合中 它使用多个Hash函数将一个元素映射成一个位阵列Bit array中的一个点将Bit array理解为一个二进制数组数组元素是0或1 当一个元素加入集合时通过N个散列函数将这个元素映射到一个Bit array中的N个点把它们设置为1 执行三个函数判断有没有结果是0是0就代表这个不存在就不查询数据库 检索某个元素时再通过这N个散列函数对这个元素进行映射根据映射找到具体位置的元素如果这些位置有任何一个0则该元素一定不存在如果都是1很可能存在误判 哈希函数的基本特性 同一个数使用同一个哈希函数计算哈希值其哈希值总是一样的 对不同的数用相同的哈希函数计算哈希值其哈希值可能一样这称为哈希冲突 哈希函数通常是单向的不可逆的即从哈希值不能逆向推导出原始输入。这使得哈希函数适用于加密和安全应用 为什么会存在误判 主要原因是哈希冲突。布隆过滤器使用多个哈希函数将输入的元素映射到位数组中的多个位置当多个不同的元素通过不同的哈希函数映射到相同的位数组位置时就发生了哈希冲突 由于哈希函数的有限性不同的元素可能会映射到相同的位置上这种情况下即使元素不在布隆过滤器中可能产生误判即布隆过滤器判断元素在集合中 如何降低误判率 增加Bit array空间减少哈希冲突优化散列函数使用更多的散列函数 如何使用布隆过滤器 将要查询的元素通过N个散列函数提前全部映射到Bit array中比如查询服务信息需要将全部服务的id提前映射到Bit array中当去查询元素是否在数据库存在时从布隆过滤器查询即可如果哈希函数返回0则表示肯定不存在 使用布隆过滤器就是把数据库的服务信息全部同步到Bit array 布隆过滤器的优点是二进制数组占用空间少插入和查询效率高效 缺点是存在误判率并且删除困难因为同一个位置由于哈希冲突可能存在多个元素删除某个元素可能删除了其它元素 布隆过滤器的应用场景 1.海量数据去重比如URL去重搜索引擎爬虫抓取网页使用布隆过滤器可以快速判定一个URL是否已经被爬取过避免重复爬取 2.垃圾邮件过滤使用布隆过滤器可以用于快速判断一个邮件地址是否是垃圾邮件发送者对于海量的邮件地址布隆过滤器可以提供高效的判定 3.安全领域在网络安全中布隆过滤器可以用于检查一个输入值是否在黑名单中用于快速拦截一些潜在的恶意请求 4.避免缓存穿透通过布隆过滤器判断是否不存在如果不存在则直接返回 如何代码实现布隆过滤器 使用redit的bitmap位图结构实现 使用redisson实现 使用google的Guava库实现 下边举例说明 引入依赖 dependencygroupIdcom.google.guava/groupIdartifactIdguava/artifactIdversion28.2-jre/version /dependency测试代码 package com.jzo2o.foundations.service;import java.nio.charset.Charset;public class BloomFilterExample {public static void main(String[] args) {// 创建一个布隆过滤器预期元素数量为1000误判率为0.01BloomFilterString bloomFilter BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), 1000, 0.01);// 添加元素到布隆过滤器bloomFilter.put(example1);bloomFilter.put(example2);bloomFilter.put(example3);// 测试元素是否在布隆过滤器中System.out.println(bloomFilter.mightContain(example1)); // trueSystem.out.println(bloomFilter.mightContain(example4)); // false} }在上述代码中我们创建了一个预期包含1000个元素、误判率为0.01的布隆过滤器。然后我们向布隆过滤器中添加了三个元素“example1”、“example2” 和 “example3”并测试了几个元素是否在布隆过滤器中 请注意误判率是你可以调整的一个参数。较低的误判率通常需要更多的空间和计算资源 3.小结 什么是缓存穿透如何解决缓存穿透 什么是布隆过滤器如何使用布隆过滤器 本项目使用缓存空值或特殊值的方法去解决缓存穿透 1.4.2 缓存击穿问题 1.什么是缓存击穿 缓存击穿发生在访问热点数据大量请求访问同一个热点数据当热点数据失效后同时去请求数据库瞬间耗尽数据库资源导致数据库无法使用 比如某手机新品发布当缓存失效时有大量并发到来导致同时去访问数据库 2.解决方案 1.使用锁 单体架构下单进程内可以使用同步锁控制查询数据库的代码只允许有一个线程去查询数据库查询得到数据库存入缓存 synchronized(obj){//查询数据库//存入缓存 }分布式架构下多个进程之间可以使用分布式锁进行控制 // 获取分布式锁对象 RLock lock redisson.getLock(myLock); try {// 尝试加锁最多等待100秒加锁后自动解锁时间为30秒boolean isLocked lock.tryLock(100, 30, java.util.concurrent.TimeUnit.SECONDS);if (isLocked) {//查询数据库//存入缓存} else {System.out.println(获取锁失败可能有其他线程持有锁);} } catch (InterruptedException e) {e.printStackTrace(); } finally {// 释放锁lock.unlock();System.out.println(释放锁…); }2.热点数据不过期 可以由后台程序提前将热点数据加入缓存缓存过期时间不过期由后台程序做好缓存同步 例如当服务上架后将服务信息缓存到redis且永不过期此时需要使用put注解 3.缓存预热 分为提前预热、定时预热 提前预热就是提前写入缓存 定时预热是使用定时程序去更新缓存 4.热点数据查询降级处理 对热点数据查询定义单独的接口当缓存中不存在时走降级方法避免查询数据库 小结 什么是缓存击穿如何解决缓存击穿 本项目对热点数据定时预热使用定时任务刷新缓存保证缓存永不过期解决缓存穿透问题 1.4.3 缓存雪崩问题 1.什么是缓存雪崩 缓存雪崩是缓存中大量key失效后当高并发到来时导致大量请求到数据库瞬间耗尽数据库资源导致数据库无法使用 比如对某信息设置缓存过期时间为30分钟在大量请求同时查询该类信息时此时就会有大量的同类信息存在相同的过期时间一旦失效将同时失效造成雪崩问题 2.解决方案 1.使用锁进行控制 思路同缓存击穿 2.对同一类型信息的key设置不同的过期时间 通常对一类信息的key设置的过期时间是相同的这里可以在原有固定时间的基础上加上一个随机时间使它们的过期时间都不相同 具体实现在framework工程中定义缓存管理器指定过期时间加上随机数 3.缓存定时预热 不用等到请求到来再去查询数据库存入缓存可以提前将数据存入缓存。使用缓存预热机制通常有专门的后台程序去将数据库的数据同步到缓存 小结 什么是缓存雪崩如何解决缓存雪崩 本项目对key设置不同的过期时间解决缓存雪崩问题 1.4.4 缓存不一致问题 1.什么是缓存不一致问题 缓存不一致问题是指当发生数据变更后该数据在数据库和缓存中是不一致的此时查询缓存得到的并不是与数据库一致的数据 缓存不一致会导致什么后果比如查看商品信息的价格与真实价格不一致影响用户体验如果直接使用缓存中的价格去计算订单金额更会导致计算结果错误 造成缓存不一致的原因可能是在写数据库和写缓存两步存在异常也可能是并发所导致 写数据库和写缓存导致不一致称为双写不一致比如先更新数据库成功了更新缓存时失败了最终导致不一致 并发导致缓存不一致举例如下 执行流程 线程1先写入数据库X当去写入缓存X时网络卡顿 线程2先写入数据库Y 线程2再写入缓存Y 线程1 写入缓存旧值X覆盖了新值Y 即使先写入缓存再写数据在并发环境也可能存在问题 流程 线程1先写入缓存X当去写入数据库X时网络卡顿 线程2先写入缓存Y 线程2再写入数据库Y 线程1 写入数据库旧值X覆盖了新值Y 2.解决方案 如何解决并发环境下双写不一致的问题 1 使用分布式式锁 流程 线程1申请分布式锁拿到锁。此时其它线程无法获取同一把锁 线程1写数据库写缓存操作完成释放锁 线程2申请分布锁成功写数据库写缓存 对双写的操作每个线程顺序执行 对操作异常问题仍需要解决写数据库成功写缓存失败了数据库需要回滚此时就需要使用分布式事务组件 使用分布式锁解决双写一致性不仅性能低下复杂度增加 2 延迟双删 既然双写操作存在不一致我们把写缓存改为删除缓存呢 先写数据库再删除缓存如果删除缓存失败了缓存也就不一致了那我们改为先删除缓存再写数据库 执行流程 线程1删除缓存 线程2读缓存发现没有数据此时查询数据库拿到旧数据写入缓存 线程1写入数据库 即使线程1删除缓存、写数据库操作后线程2再去查询缓存也可能存在问题 线程1向主数据库写线程2向从数据库查询流程如下 线程1删除缓存 线程1向主数据库写数据向从数据库同步 线程2查询缓存没有数据查询从数据库得到旧数据 线程2将旧数据写入缓存 解决上边的问题采用延迟双删 线程1先删除缓存再写入主数据库延迟一定时间再删除缓存 上图线程1的动作简化为下图 延迟多长时间呢 延迟主数据向从数据库同步的时间间隔如果延迟时间设置不合理也会导致数据不一致 3 异步同步 延迟双删的目的也是为了保证最终一致性即允许缓存短暂不一致最终保证一致性 保证最终一致性的方案有很多比如通过MQ、Canal、定时任务都可以实现 Canal是一个数据同步工具读取MySQL的binlog日志拿到更新的数据再通过MQ发送给异步同步程序最终由异步同步程序写到redis。此方案适用于对数据实时性有一定要求的场景 通过Canal加MQ异步任务方式流程如下 流程如下 线程1写数据库 canal读取binlog日志将数据变化日志写入mq 同步程序监听mq接收到数据变化的消息 同步程序解析消息内容写入redis写入redis成功正常消费完成消息从mq删除 定时任务方式流程如下 专门启动一个数据同步任务定时读取数据同步到redis此方式适用于对数据实时性要求不强更新不频繁的数据 线程1写入数据库业务数据表变化日志表 同步程序读取数据库变化日志表根据变化日志内容写入redis同步完成删除变化日志 小结 如何保证缓存一致性 2.缓存实现 2.1 开通区域列表缓存实现 目标 能说出项目中的缓存方案 实现开通区域列表缓存完成查询缓存、删除缓存 2.1.1 缓存方案分析 根据本项目门户的需求可知共有以下几块信息需要缓存 下边分析第一个开通区域列表的缓存方案 查询缓存查询已开通区域列表如果没有缓存则查询数据库并将查询结果进行缓存如果存在缓存则直接返回 启用区域删除开通区域信息缓存再次查询将缓存新的开通区域列表。 禁用区域删除开通区域信息缓存删除该区域下的其它缓存信息包括首页服务列表服务类型列表热门服务列表。 定时任务每天凌晨缓存已开通区域列表 2.1.2 查询缓存实现 下边我们先实现开通区域列表查询缓存 首先把测试环境准备好 启动jzo2o-gateway、jzo2o-publics、jzo2o-customer、jzo2o-foundations打开小程序开发工具 打开小程序点击首页左上角的地址进入服务地址城市选择页面 在定位界面显示已开通城市列表已开通城市是指在区域管理中所有启用的区域信息 跟踪Network找到开通区域列表的URL:/foundations/consumer/region/activeRegionList 打开jzo2o-foundations工程根据接口地址找到具体的代码 找到接口 package com.jzo2o.foundations.controller.consumer;/** 区域表 前端控制器/ RestController(consumerRegionController) RequestMapping(/consumer/region) Api(tags 用户端 - 区域相关接口) public class RegionController {Resourceprivate IRegionService regionService;GetMapping(/activeRegionList)ApiOperation(已开通服务区域列表)public ListRegionSimpleResDTO activeRegionList() {return regionService.queryActiveRegionListCache();}}找到service方法如下 在service方法上添加Spring cache注解 Override Cacheable(value RedisConstants.CacheName.JZ_CACHE, key ACTIVE_REGIONS, cacheManager RedisConstants.CacheManager.FOREVER) //永不过期 public ListRegionSimpleResDTO queryActiveRegionListCache() {return queryActiveRegionList(); }说明 key: 当key用一个固定字符串时需要在双引号中用单引号括起来如下所示key “‘ACTIVE_REGIONS’” cacheManager RedisConstants.CacheManager.FOREVER设置了缓存永不过期 重启jzo2o-foundations工程进行测试观察redis成功缓存开通区域列表 3.启用区域 启用一个新区域已经开通区域列表需要变更该如何实现呢 启用区域后删除已开通区域列表缓存当去查询开通区域列表时重新缓存最新的开通区域列表 接口的代码如下 找到service代码修改如下 /** 区域管理/ Service public class RegionServiceImpl extends ServiceImplRegionMapper, Region implements IRegionService {/* 区域启用* param id 区域id/ Override CacheEvict(value RedisConstants.CacheName.JZ_CACHE, key ACTIVE_REGIONS) public void active(Long id) { …… }4.禁用区域 如果是禁用一个区域则需要删除开通区域列表缓存 禁用区域除了删除开通区域列表还需要删除首页服务列表、热门服务列表等所以这里使用Caching注解 找到禁用区域的代码修改如下 /** 区域管理**/ Service public class RegionServiceImpl extends ServiceImplRegionMapper, Region implements IRegionService {OverrideCaching(evict {CacheEvict(value RedisConstants.CacheName.JZ_CACHE, key ACTIVE_REGIONS) // todo:删除首页服务列表缓存})public void deactivate(Long id) {……小结 项目哪里进行了缓存缓存方案是什么 项目中如何保证缓存的一致性
- 上一篇: 网站扩展名丹东供求园
- 下一篇: 网站栏目建设图php怎么做p2p网站
