截止到今天为止,我自身感觉是有很大的进步,今天也一个人独立写了很多的接口,相比较于第一次简直是天差地别。今天在听课的时候也有很多的收获。开心
目录
前言:
今日完结任务:
今日收获:
1.实现了缓存菜品的功能:
2.实现了缓存套餐的功能:
3.购物车相关接口:
杂项知识点:
总结:
这个功能的出发点是因为:在项目上线之后,会有大量的并发请求,而我们以前在查询菜品的时候,采用的是直接从数据库中读取数据返回给前端的操作。但这是一个I/O操作,大量的并发I/O操作会狠狠的拷打我们的后端服务器。而用户端的体验也会大大下降(查询数据满慢造成卡顿感受)
因此为了提高我们的用户效率,我们采用这样一种思想:建立一块缓存区,在用户查询对应数据的时候,先看看缓存区有没有,如果缓存区有,直接发送缓存区中的数据,如果缓存区没有,再查询数据库,并且把查询到的数据同时存到缓冲区中,便捷下次查询的效率。
这种思想其实很常见,我们的DNS服务商也在使用这种思想,他们会缓存常见域名对应的IP地址,这样在DNS转换的时候,就不需要再向各级地址进行查询,大大优化了耗时
而我们建立缓存区的方法是使用Redis数据库,在前面我们就介绍过Redis,他是一个存储在内存中的键值类型的数据库,这大大优化了查询效率。
在这里我们贴一段在查询菜品的时候应用Redis优化的代码
其实Spring 就已经为我们提供了通过注解的方式来解决这些问题,在后面我们也会逐一介绍
基于和缓存菜品一样的需求,我们来实现缓存套餐,而我们在这里用到了一个依赖:Spring Cache
Spring Cache是Spring框架提供的一个缓存抽象层,它允许开发者轻松地在应用程序中添加缓存功能。通过使用Spring Cache,开发者可以将常用的数据或计算结果缓存起来,以提高应用程序的性能和响应速度。
Spring Cache的工作原理是基于AOP(面向切面编程)和注解。开发者只需在相应的方法上添加缓存注解,Spring Cache就会使用缓存来缓存方法的返回值。当下次再次调用该方法时,Spring Cache会首先查询缓存中是否存在该返回值,并直接返回缓存结果,避免了重复的计算或数据库查询。
Spring Cache支持多种缓存存储的后端实现,包括基于内存的缓存(如ConcurrentMapCache)、基于Redis的分布式缓存、基于Ehcache的本地缓存等。开发者可以根据项目需求选择合适的缓存实现。
引入依赖:
org.springframework.boot
spring-boot-starter-cache
然后我们就可以通过调用相关注解的方式来达到缓存套餐的功能:(在这里我们的底层缓存实现还是redis)
购物车相关接口其实收获不大,还是普通的curd操作。但是一通写下来确实是让我的熟练度更加好了
1.如何保持redis与数据库中的数据的一致性?
因为我们在添加redis作为缓冲区之后,如果缓冲区中存在数据,我们是直接从缓冲区拿数据的,如果我们更改了数据库,可能就会造成数据库与缓冲区数据不一致的情况。
读写双写(Write-through):在更新数据库时,同时更新Redis缓存。这意味着在写入数据库的同时,将相同的数据写入Redis缓存。这种方式确保了数据库和缓存中的数据始终保持一致。但是需要注意的是,双写操作会增加系统的写入负载和延迟,并且需要保证写入操作的原子性。
读写更新(Write-behind):在更新数据库时,延迟更新Redis缓存。这种方式先更新数据库,然后异步地更新Redis缓存,以提高写入的性能和响应速度。在这种情况下,可能会出现一小段时间内数据库和缓存数据的不一致,但后续的读取操作会从数据库中获取最新的数据并更新缓存。
缓存失效策略:通过在缓存中设置适当的过期时间或失效策略,确保缓存中的数据在一定时间后会过期并从数据库中重新加载。这样可以保证在数据更新或过期后,下一次读取操作将从数据库中获取最新的数据,并更新缓存。这种方式适用于数据变化不频繁、对数据实时性要求不高的场景。
发布订阅模式(Pub/Sub):使用Redis的发布订阅功能,当数据库中的数据发生变化时,通过发布消息的方式通知订阅者(Redis缓存)进行更新。这样可以保证在数据发生变化时,及时通知Redis缓存更新,以保持数据的一致性。
2.什么是redis三大问题:穿透,击穿,雪崩
穿透(Cache Penetration):当一个不存在的键被频繁查询时,会导致缓存无效并且每次查询都需要访问数据库。这种情况下,恶意用户可以通过构造不存在的键来绕过缓存,直接请求数据库。这不仅浪费了数据库的资源,还可能导致数据库压力过大。为了解决穿透问题,可以使用布隆过滤器或者在查询得到空结果时也进行缓存,设置一个较短的过期时间。
击穿(Cache Breakdown):当一个热点键过期或被清除时,同时又有大量的请求访问该键,导致这些请求直接访问数据库,称为击穿。这种情况下,数据库会承受巨大的压力,可能导致宕机或性能下降。为了解决击穿问题,可以使用互斥锁或者分布式锁,保证只有一个请求能够访问数据库,并在请求获取到数据后更新缓存。
雪崩(Cache Avalanche):当大量的缓存键在同一时间失效,或者缓存服务器发生故障,导致大量的请求直接访问数据库,称为雪崩效应。这种情况下,数据库会承受巨大的压力,可能导致宕机或性能下降。为了解决雪崩问题,可以采用多级缓存架构,将请求分散到多个缓存服务器,或者使用热点数据预加载的方式,提前加载热门数据到缓存中。
3.spring cache中的@Cacheable、@CachePut、@CacheEvict @三个注解
@Cacheable注解:用于在方法执行前检查缓存中是否存在对应的值,如果存在则直接返回缓存结果,否则执行方法并将返回值存入缓存中。该注解常用于读取操作。
@Cacheable(cacheNames = "myCache", key = "#param")
public Object myMethod(String param) {
// 方法体
}
#param
表示使用方法的参数作为键。@CachePut注解:用于将方法的返回值存入缓存中,无论缓存中是否已存在该键,都会将返回值存入缓存。该注解常用于更新操作。
@CachePut(cacheNames = "myCache", key = "#param")
public Object myMethod(String param) {
// 方法体
}
@CacheEvict注解:用于从缓存中清除对应的值。该注解常用于删除操作。
@CacheEvict(cacheNames = "myCache", key = "#param")
public void myMethod(String param) {
// 方法体
}
除了这三个注解以外,还有一个启动类注解@EnableCaching,标识在启动类上,表示开启缓存注解功能
创造缓冲区来减少对数据库的直接查询,提高访问效率是一个不错的思想,他巧妙的利用的Redis的存储特性。在实际业务开发中也是一个比较常见的需求,因此今天还是有学到一点好东西的。
如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!