【苍穹外卖 | 项目日记】第六天

前言:

        截止到今天为止,我自身感觉是有很大的进步,今天也一个人独立写了很多的接口,相比较于第一次简直是天差地别。今天在听课的时候也有很多的收获。开心

【苍穹外卖 | 项目日记】第六天_第1张图片

目录

前言:

今日完结任务:

今日收获:

1.实现了缓存菜品的功能:

2.实现了缓存套餐的功能:

3.购物车相关接口:

杂项知识点:

总结:


 

今日完结任务:

  • 1.实现了缓存菜品功能
  • 2.实现了缓存套餐功能
  • 3.实现了添加购物车接口
  • 4.实现了查看购物车接口
  • 5.实现了清空购物车接口
  • 6.实现了删除购物车商品接口

今日收获:

1.实现了缓存菜品的功能:

这个功能的出发点是因为:在项目上线之后,会有大量的并发请求,而我们以前在查询菜品的时候,采用的是直接从数据库中读取数据返回给前端的操作。但这是一个I/O操作,大量的并发I/O操作会狠狠的拷打我们的后端服务器。而用户端的体验也会大大下降(查询数据满慢造成卡顿感受)

因此为了提高我们的用户效率,我们采用这样一种思想:建立一块缓存区,在用户查询对应数据的时候,先看看缓存区有没有,如果缓存区有,直接发送缓存区中的数据,如果缓存区没有,再查询数据库,并且把查询到的数据同时存到缓冲区中,便捷下次查询的效率。

这种思想其实很常见,我们的DNS服务商也在使用这种思想,他们会缓存常见域名对应的IP地址,这样在DNS转换的时候,就不需要再向各级地址进行查询,大大优化了耗时

而我们建立缓存区的方法是使用Redis数据库,在前面我们就介绍过Redis,他是一个存储在内存中的键值类型的数据库,这大大优化了查询效率。

在这里我们贴一段在查询菜品的时候应用Redis优化的代码

【苍穹外卖 | 项目日记】第六天_第2张图片

 其实Spring 就已经为我们提供了通过注解的方式来解决这些问题,在后面我们也会逐一介绍

2.实现了缓存套餐的功能:

基于和缓存菜品一样的需求,我们来实现缓存套餐,而我们在这里用到了一个依赖: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)

【苍穹外卖 | 项目日记】第六天_第3张图片
 他的常用注解我会在后面介绍

3.购物车相关接口:

        购物车相关接口其实收获不大,还是普通的curd操作。但是一通写下来确实是让我的熟练度更加好了

杂项知识点:

1.如何保持redis与数据库中的数据的一致性?

因为我们在添加redis作为缓冲区之后,如果缓冲区中存在数据,我们是直接从缓冲区拿数据的,如果我们更改了数据库,可能就会造成数据库与缓冲区数据不一致的情况。

  1. 读写双写(Write-through):在更新数据库时,同时更新Redis缓存。这意味着在写入数据库的同时,将相同的数据写入Redis缓存。这种方式确保了数据库和缓存中的数据始终保持一致。但是需要注意的是,双写操作会增加系统的写入负载和延迟,并且需要保证写入操作的原子性。

  2. 读写更新(Write-behind):在更新数据库时,延迟更新Redis缓存。这种方式先更新数据库,然后异步地更新Redis缓存,以提高写入的性能和响应速度。在这种情况下,可能会出现一小段时间内数据库和缓存数据的不一致,但后续的读取操作会从数据库中获取最新的数据并更新缓存。

  3. 缓存失效策略:通过在缓存中设置适当的过期时间或失效策略,确保缓存中的数据在一定时间后会过期并从数据库中重新加载。这样可以保证在数据更新或过期后,下一次读取操作将从数据库中获取最新的数据,并更新缓存。这种方式适用于数据变化不频繁、对数据实时性要求不高的场景。

  4. 发布订阅模式(Pub/Sub):使用Redis的发布订阅功能,当数据库中的数据发生变化时,通过发布消息的方式通知订阅者(Redis缓存)进行更新。这样可以保证在数据发生变化时,及时通知Redis缓存更新,以保持数据的一致性。

 2.什么是redis三大问题:穿透,击穿,雪崩

  1. 穿透(Cache Penetration):当一个不存在的键被频繁查询时,会导致缓存无效并且每次查询都需要访问数据库。这种情况下,恶意用户可以通过构造不存在的键来绕过缓存,直接请求数据库。这不仅浪费了数据库的资源,还可能导致数据库压力过大。为了解决穿透问题,可以使用布隆过滤器或者在查询得到空结果时也进行缓存,设置一个较短的过期时间。

  2. 击穿(Cache Breakdown):当一个热点键过期或被清除时,同时又有大量的请求访问该键,导致这些请求直接访问数据库,称为击穿。这种情况下,数据库会承受巨大的压力,可能导致宕机或性能下降。为了解决击穿问题,可以使用互斥锁或者分布式锁,保证只有一个请求能够访问数据库,并在请求获取到数据后更新缓存。

  3. 雪崩(Cache Avalanche):当大量的缓存键在同一时间失效,或者缓存服务器发生故障,导致大量的请求直接访问数据库,称为雪崩效应。这种情况下,数据库会承受巨大的压力,可能导致宕机或性能下降。为了解决雪崩问题,可以采用多级缓存架构,将请求分散到多个缓存服务器,或者使用热点数据预加载的方式,提前加载热门数据到缓存中。

 3.spring cache中的@Cacheable、@CachePut、@CacheEvict  @三个注解

  1. @Cacheable注解:用于在方法执行前检查缓存中是否存在对应的值,如果存在则直接返回缓存结果,否则执行方法并将返回值存入缓存中。该注解常用于读取操作。

    @Cacheable(cacheNames = "myCache", key = "#param")
    public Object myMethod(String param) {
        // 方法体
    }
    
    • cacheNames:指定缓存名称,对应于配置中的缓存管理器中的缓存名。
    • key:指定缓存的键,可以通过SpEL表达式指定,例如#param表示使用方法的参数作为键。
  2. @CachePut注解:用于将方法的返回值存入缓存中,无论缓存中是否已存在该键,都会将返回值存入缓存。该注解常用于更新操作。

    @CachePut(cacheNames = "myCache", key = "#param")
    public Object myMethod(String param) {
        // 方法体
    }
    
    • cacheNames:缓存名称。 
    • key:缓存键。
  3. @CacheEvict注解:用于从缓存中清除对应的值。该注解常用于删除操作。

    @CacheEvict(cacheNames = "myCache", key = "#param")
    public void myMethod(String param) {
        // 方法体
    }
    
    • cacheNames:缓存名称。
    • key:缓存键。

 除了这三个注解以外,还有一个启动类注解@EnableCaching标识在启动类上,表示开启缓存注解功能

【苍穹外卖 | 项目日记】第六天_第4张图片

总结:

        创造缓冲区来减少对数据库的直接查询,提高访问效率是一个不错的思想,他巧妙的利用的Redis的存储特性。在实际业务开发中也是一个比较常见的需求,因此今天还是有学到一点好东西的。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

69e9169c980f43e0aad31ff9ada88a9c.png

 

你可能感兴趣的:(【苍穹外卖】,redis,数据库,缓存,学习,java)