【Redis(8)】Spring Boot整合Redis和Guava,解决缓存穿透、缓存击穿、缓存雪崩等缓存问题

server/2024/10/20 10:04:26/

缓存技术的挑战及设计方案我们介绍了使用缓存技术可能会遇到的一些问题,那么如何解决这些问题呢?

在构建缓存系统时,Spring Boot和Redis的结合提供了强大的支持,而Guava的LoadingCache则为缓存管理带来了便捷的解决方案。下面我将介绍如何通过整合Spring Boot、Redis和Guava来实现一个解决缓存穿透、缓存击穿、缓存雪崩、缓存污染和缓存数据一致性问题的缓存方案。

一、整合Spring Boot与Redis

首先,我们需要在Spring Boot项目中整合原生Redis客户端。这可以通过添加Spring Boot Redis依赖来实现。

二、引入Guava

Guava的LoadingCache是一个高级缓存工具,它支持自动加载、缓存数据的自动刷新和监听器通知。

三、工具类

下面是一个三高缓存工具类的实现,它整合了Spring Boot、Redis和Guava的LoadingCache。这个工具类旨在解决缓存穿透、缓存击穿、缓存雪崩、缓存污染和缓存数据一致性问题。

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;public class CacheUtil<DataLoader extends CacheUtil.DataLoaderInterface> {private final StringRedisTemplate stringRedisTemplate;private final ValueOperations<String, String> valueOperations;private final LoadingCache<String, String> loadingCache;private final DataLoader dataLoader;@Autowiredpublic CacheUtil(StringRedisTemplate stringRedisTemplate, DataLoader dataLoader) {this.stringRedisTemplate = stringRedisTemplate;this.valueOperations = stringRedisTemplate.opsForValue();this.dataLoader = dataLoader;// 初始化Guava LoadingCache// 设置最大容量,避免缓存污染// 设置写入后过期时间,避免缓存雪崩// 使用锁机制,避免缓存击穿this.loadingCache = CacheBuilder.newBuilder().maximumSize(10000).expireAfterWrite(10, TimeUnit.MINUTES).build(new CacheLoader<String, String>() {@Overridepublic String load(String key) throws Exception {// 当缓存未命中时,调用数据加载器的方法从数据库加载数据return dataLoader.loadDataFromDatabase(key);}});}public String get(String key) {try {// 通过Guava LoadingCache获取数据// 自动处理缓存穿透和击穿return loadingCache.get(key);} catch (ExecutionException e) {// 异常处理,返回nullreturn null;}}public void set(String key, String value) {// 同时更新Redis和Guava LoadingCache// 保持数据一致性valueOperations.set(key, value);loadingCache.put(key, value);}public void update(String key, String value) {// 更新缓存数据,解决数据一致性问题set(key, value);}public void insert(String key, String value) {// 插入前检查缓存,避免缓存污染if (get(key) == null) {set(key, value);}}public void delete(String key) {// 删除Redis和Guava LoadingCache中的数据// 保持数据一致性valueOperations.delete(key);loadingCache.invalidate(key); // 使缓存项失效}// 用于在数据库更新后刷新缓存public void refreshCache(String key) {loadingCache.invalidate(key);}// 数据加载器接口,调用者需要实现该接口以提供数据加载逻辑public interface DataLoaderInterface {String loadDataFromDatabase(String key);}
}

四、使用示例

  • 实现数据加载器接口:创建一个类实现CacheUtil.DataLoaderInterface接口,提供具体的数据加载逻辑。
public class UserCacheDataLoader implements CacheUtil.DataLoaderInterface {private final UserService userService; // 假设这是您的UserService@Autowiredpublic UserCacheDataLoader(UserService userService) {this.userService = userService;}@Overridepublic String loadDataFromDatabase(String key) {// 根据键(例如用户ID)从数据库加载数据User user = userService.findById(key);if (user != null) {return user.toString(); // 将用户信息转换为字符串}return null; // 用户不存在}
}
  • 配置Spring Bean:在Spring配置中注册CacheUtil Bean。
@Configuration
public class CacheConfig {@Beanpublic CacheUtil<UserCacheDataLoader> userCacheUtil(UserCacheDataLoader userCacheDataLoader) {// 假设已经配置好StringRedisTemplate stringRedisTemplate = stringRedisTemplate(); return new CacheUtil<>(stringRedisTemplate, userCacheDataLoader);}// 其他配置...
}
  • 在应用中使用:在需要缓存的地方注入CacheUtil并使用它。
@RestController
@RequestMapping("/users")
public class UserController {private final CacheUtil<UserCacheDataLoader> userCacheUtil;@Autowiredpublic UserController(CacheUtil<UserCacheDataLoader> userCacheUtil) {this.userCacheUtil = userCacheUtil;}@GetMapping("/{userId}")public String getUserDetails(@PathVariable String userId) {// 使用CacheUtil的get方法来获取缓存数据return userCacheUtil.get(userId);}// 更新缓存数据userCacheUtil.update(key, value);// 插入缓存数据userCacheUtil.insert(key, value);// 删除缓存数据userCacheUtil.delete(key);// 数据库更新后刷新缓存userCacheUtil.refreshCache(key);
}

 

注意:

  • 请确保StringRedisTemplate和数据加载器(如UserCacheDataLoader)已经正确配置并注入到CacheUtil中。
  • 根据业务逻辑的复杂性,loadDataFromDatabase方法可能需要合理的超时和重试策略。
  • 在实际部署前,进行充分的测试,确保缓存加载逻辑在各种情况下都能正常工作。

 


http://www.ppmy.cn/server/7630.html

相关文章

【JavaEE初阶】网络原理|认识协议|协议分层|TCP/IP模型|封装和分用

一、认识协议 1.概念 简单来说&#xff1a;就是一种通信双方&#xff0c;对于通信规则的约定&#xff08;标准&#xff09;&#xff0c;一定是通信双方都认可的 但是这个协议不一定是认可面非常广的&#xff0c;即使是两个人之间的也可叫做协议 就好⽐⻅⽹友&#xff0c;彼此…

分布式与集群区别

1、提供服务是否相同 分布式&#xff1a;不同的机器上部署的是不同的服务模块&#xff0c;对外提供不同的服务 集群&#xff1a;不同机器上部署的是同样的模块&#xff0c;对外提供同样的服务 2、目的 分布式&#xff1a;分解任务&#xff0c;用来应对高并发。 集群&#…

解释一下“暂存区”的概念,在Git中它扮演什么角色?

文章目录 暂存区在Git中的概念与作用什么是暂存区&#xff08;Staging Area&#xff09;暂存区的位置和结构 暂存区在Git工作流程中的角色1. 分离工作区与版本库的交互示例代码与操作步骤示例1&#xff1a;将工作区的修改添加至暂存区 2. 控制提交内容的粒度示例2&#xff1a;分…

Hadoop——Yarn 生产环境核心参数

1. ResourceManager 相关参数&#xff1a; yarn.resourcemanager.hostname&#xff1a;ResourceManager 的主机名。yarn.resourcemanager.webapp.address&#xff1a;ResourceManager 的 Web 应用程序地址。yarn.resourcemanager.scheduler.address&#xff1a;ResourceManage…

突破编程_C++_网络编程(Boost.Asio(简介))

1 Boost.Asio 概述 注意&#xff1a;本教程中 Boost.Asio 选用的是 1.80.0 版本。 1.1 基本介绍 Boost.Asio 是一个用于网络和底层 I/O 编程的 C 库&#xff0c;它的核心在于异步输入与输出&#xff08;Asynchronous Input and Output&#xff09;。其高效、灵活和平台无关性…

Qt 拖放功能详解:理论与实践并举的深度指南

拖放&#xff08;Drag and Drop&#xff09;作为一种直观且高效的用户交互方式&#xff0c;在现代图形用户界面中扮演着重要角色。Qt 框架提供了完善的拖放支持&#xff0c;允许开发者在应用程序中轻松实现这一功能。本篇博文将详细阐述Qt拖放机制的工作原理&#xff0c;结合详…

桐乡上元——新概念英语对高考有用吗?

新概念英语对高考有用吗&#xff1f; 新概念英语是一套经典的教材&#xff0c;从90后开始到现在在上小学的10后&#xff0c;应该都或多或少学过这套教材&#xff0c;说是几代人共同的青春回忆也不夸张&#xff0c;它的地位堪比五年高考三年模拟。它的作者也是国内外英语大咖&a…

windows驱动开发-WDM框架(一)

在前面的文章中解释过&#xff0c;NT5.0之后windows确定了新的架构Windows Driver Model (WDM)&#xff0c;在Vista之后又推出了Windows Driver Framework(WDF)&#xff0c;这两个都属于驱动程序框架&#xff0c;那么它们的之间的关系是怎样的&#xff1f; WDF是对WDM进行的封…