您现在的位置是:首页 > 正文

SpringBoot整合缓存(Caffeine、Redis)

2024-02-01 02:34:02阅读 3

SpringBoot整合缓存

注解介绍

@EnableCaching

标记在CacheManager统一配置类,需要配合@Configuration使用

@Cachable

标记在需要使用缓存的实现类上,一般用于查询操作。当该方法输入参数对应的缓存数据不存在与缓存引擎中(类似Redis)时,则会自动生成相关缓存;若存在则直接获取缓存结果。

@CachePut

标记在需要使用缓存的实现类上,一般用于更新操作。无论如何都会执行方法逻辑,更新到缓存引擎中

@CacheEvict

标记在需要使用缓存的实现类上,一般用于更新操作。直接清除该缓存

优缺点

优点:可以快速的应用缓存,不必要专业的中间件(例如:CaffeineCache
缺点:无法精细的对缓存做业务处理,只能按照Spring整合缓存提供的逻辑执行(例如:RedisCache)。

依赖

<!--Spring Boot相关-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<version>2.6.8</version>
</dependency>
<!--CaffeineCache-->
<dependency>
	<groupId>com.github.ben-manes.caffeine</groupId>
	<artifactId>caffeine</artifactId>
	<version>2.5.5</version>
</dependency>
<!--Redis-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
	<version>2.6.8</version>
</dependency>
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
	<version>3.7.1</version>
</dependency>

配置文件yml

spring:
  redis:
    host: 127.0.0.1
    port: 6379

整合Caffeine

步骤

1. 在自定义的CacheConfig中配置一个CaffeineCacheManager@Bean

在这里插入图片描述

2. 在实现类中通过@Cachable进行标注(即表示使用哪个引擎CacheManager)

在这里插入图片描述

  • 其中,value值对应图一中创建的缓存名称,cacheManager(必填)对应注入的@Bean的名字,
  • 因为如果CachesConfig中存在不同缓存引擎@Bean时(即多个CacheManager都来自一个接口),就会出现@Bean冲突的问题。
  • 解决问题的关键就是使用@Primary指定默认先加载哪个bean,或者就是当下的情况,直接指定cacheManager。

3. 测试缓存结果

在这里插入图片描述
在这里插入图片描述

代码

CachesConfig配置类
@Configuration
@EnableCaching
public class CachesConfig {
	@Bean(value = "getCaffeineCacheManager")
	public CaffeineCacheManager cacheManager() {
		CaffeineCacheManager cacheManager = new CaffeineCacheManager();
		Cache<Object, Object> cache = Caffeine.newBuilder()
				.expireAfterWrite(5, TimeUnit.SECONDS)
				.maximumSize(10_000)
				.build();
		cacheManager.registerCustomCache("demoCache",cache);
		return cacheManager;
	}
}

CachesController控制层

@RestController
@RequestMapping(value = "cachesController")
public class CachesController {
	@Autowired
	private CachesService cachesService;
	@Autowired
	@Qualifier("getCaffeineCacheManager")
	private CaffeineCacheManager caffeineCacheManager;


	@GetMapping("playCaffeineCaches")
	public <T> T playCaffeineCaches() throws InterruptedException {
		System.out.println(cachesService.getFromDB(1));
		System.out.println(cachesService.getFromDB(1));

		// 校验缓存里的内容~~~~
		Cache demoCache = Objects.requireNonNull(caffeineCacheManager.getCache("demoCache"));
		String s = demoCache.get(1, String.class);
		System.out.println(s);
		// 由于设定Caffeine的过期时间为5s,检验超时后缓存是否失效
		TimeUnit.SECONDS.sleep(10);
		s = demoCache.get(1, String.class);
		System.out.println(s);
		return (T) s;
	}
}

CacheServiceImpl实现类

@Service
@CacheConfig(cacheNames = {"com.devilvan.config.CachesConfig"})
public class CacheServiceImpl implements CachesService {
	@Cacheable(value = {"demoCache"}, cacheManager = "getCaffeineCacheManager", key = "#id")
	@Override
	public Object getFromDB(Integer id) {
		System.out.println("模拟去db查询~~~" + id);
		return "hello cache...";
	}
}

整合Redis缓存

步骤

1. 定义一个RedisTemplate的@Bean

如果不添加其他信息直接注入一个也行
在这里插入图片描述

2. 在自定义的CacheConfig中配置一个RedisCacheManager

在这里插入图片描述

3. 在实现类中标记@Cachable@CachePut@CacheEvict注解,对应缓存的动作

在这里插入图片描述

参数

cacheManager

对应配置类中定义的缓存引擎@Bean,CacheManager的实现类

cacheNames

自定义缓存的名字,这里如果定的名字为上图中withCacheConfiguration()方法中的名字,则使用该方法参数中的配置

key

即缓存的对象ID,一般绑定方法参数,当key值在缓存中不存在时,执行逻辑并添加进缓存,存在则直接返回缓存的结果。

代码

CachesConfig配置类

/**
 * 自定义redisTemplate
 */
@Bean
public RedisTemplate<Object, Object> empRedisTemplate(
		RedisConnectionFactory redisConnectionFactory) {
	RedisTemplate<Object, Object> template = new RedisTemplate<>();
	template.setConnectionFactory(redisConnectionFactory);
	// 转换 格式
	template.setKeySerializer(new StringRedisSerializer());
	template.setValueSerializer(new StringRedisSerializer());
	template.setHashKeySerializer(new StringRedisSerializer());
	template.setHashValueSerializer(new StringRedisSerializer());
	return template;
}

/**
 * 基于SpringBoot2 对 RedisCacheManager 的自定义配置
 */
@Bean("empRedisCacheManager")
@Primary
public RedisCacheManager empRedisCacheManager(@Autowired @Qualifier("empRedisTemplate") RedisTemplate<Object,Object> redisTemplate) {
	RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
			.defaultCacheConfig()
			// 设置key为String
			.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getStringSerializer()))
			// 设置value 为自动转Json的Object
			.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()))
			// 不缓存null
			.disableCachingNullValues()
			// 缓存数据保存30s
			.entryTtl(Duration.ofSeconds(30));
	// 构造一个redis缓存管理器
	RedisCacheManager redisCacheManager = RedisCacheManager
			.RedisCacheManagerBuilder
			// Redis 连接工厂
			.fromConnectionFactory(Objects.requireNonNull(redisTemplate.getConnectionFactory()))
			// 设置默认缓存配置
			.cacheDefaults(redisCacheConfiguration)
			// 设置自定义缓存配置,缓存名为cache_user,它的过期时间为60s
			.withCacheConfiguration("cache_user", redisCacheConfiguration.entryTtl(Duration.ofSeconds(60)))
			// 上面默然缓存时间是1小时,但是可以根据cacheName来设置缓存时间
			.withCacheConfiguration("cache_post", redisCacheConfiguration.entryTtl(Duration.ofSeconds(120)))
			// 配置同步修改或删除 put/evict
			.transactionAware()
			.build();
	return redisCacheManager;
}

CachesController控制层

@GetMapping("playRedisCaches")
public <T> T playRedisCaches(@RequestParam("id") Integer id) {
	System.out.println(cachesService.getDept(id));
	System.out.println(cachesService.getDept(id));
	return (T) null;
}

@PostMapping("updateRedisCaches")
public <T> T updateRedisCaches(@RequestParam("id") Integer id) {
	System.out.println(cachesService.updateDept(id));
	System.out.println(cachesService.getDept(id));
	return (T) null;
}

@DeleteMapping("deleteRedisCaches")
public <T> T deleteRedisCaches(@RequestParam("id") Integer id) {
	cachesService.deleteDept(id);
	System.out.println(cachesService.getDept(id));
	return (T) null;
}

CachesServiceImpl实现类

@Cacheable(cacheManager = "empRedisCacheManager",cacheNames = {"dept"},key = "#id")
@Override
public String getDept(Integer id) {
	System.out.println("查询"+ id  +"号部门。" );
	int i = new Random().nextInt(65535);
	int hashCode = String.valueOf((id + i)).hashCode();
	return "Do you like what you see?" + "-->" +hashCode;
}

@CachePut(cacheManager = "empRedisCacheManager",cacheNames = {"dept"},key = "#id")
@Override
public String updateDept(Integer id) {
	System.out.println("更新"+ id  +"号部门。" );
	int i = new Random().nextInt(65535);
	int hashCode = String.valueOf((id + i)).hashCode();
	return "Do you like what you see?" + "-->" +hashCode;
}

@CacheEvict(cacheManager = "empRedisCacheManager",cacheNames = {"dept"},key = "#id")
@Override
public void deleteDept(Integer id) {
	System.out.println("删除"+ id  +"号部门。" );
}

网站文章

  • Java将JSON字符串与自定义对象之间的转化

    Java将自定义对象转化为JSON字符串JsonUtil.toJson(A);Java将JSON字符串转化为自定义对象InputStream in = req.getInputStream();String json = Streams.asString(in);A a = JsonUtil.of(json, A.class);

    2024-02-01 02:33:33
  • 算法设计与分析 第三章 动态规划

    算法设计与分析 第三章 动态规划

    一、思维导图 二、经典例题 1.矩阵链乘问题 (1)最优子结构证明: 假设有一个连续相乘的矩阵,要使相乘的次数最少。现在假设,x{i…j}是一个最优加括号方案。那么x{i…j} = x{i,k}+x{k+1,j},若x{i…k}是不是其子问题的最优解,那么一定存在一个y{i…k}为其子问题的最优解,那么一定有y{i…k}+x{k+1}

    2024-02-01 02:33:27
  • Qt QStandardItemModel用法(超级详细)

    Qt QStandardItemModel用法(超级详细)

    QStandardItemModel 是标准的以项数据(item data)为基础的标准数据模型类,通常与 QTableView 组合成 Model/View 结构,实现通用的二维数据的管理功能。本节介绍 QStandardltemModel 的使用,主要用到以下 3 个类:QStandardItemModel:基于项数据的标准数据模型,可以处理二维数据。维护一个二维的项数据数组,每个项是一...

    2024-02-01 02:33:20
  • post发送后加号丢失

    +为post特殊字符,所以传递后会丢失,要解诀这个问题,首先要加传递的内容进行加密。然后再解密。C#编码:Server.UrlEncode(ur)C#解码:Server.UrlDecodeJquery解码:decodeURIComponent(url);Jquery编码:encodeURIComponent(url);...

    2024-02-01 02:32:52
  • c语言遍历枚举,枚举类型的使用及进行循环

    该楼层疑似违规已被系统折叠隐藏此楼查看此楼1. 枚举的定义枚举类型定义的一般形式为:enum 枚举名{ 枚举值表 }; 在枚举值表中应罗列出所有可用值。这些值也称为枚举元素。例如: 该枚举名为week...

    2024-02-01 02:32:44
  • Macos下跑通全景视频开源项目fraunhoferhhi/omaf.js

    Macos下跑通全景视频开源项目fraunhoferhhi/omaf.js

    项目地址:https://github.com/fraunhoferhhi/omaf.js.git 1. 安装nginx brew install nginx 2. 下载代码 mkdir ~/omaf...

    2024-02-01 02:32:38
  • vue-element-admin 和 python django 前后端分离 开撸(新手学习,高手指点) 热门推荐

    vue-element-admin 和 python django 前后端分离 开撸(新手学习,高手指点) 热门推荐

    一、python django 项目建立 1、django安装方法:运行命令:pip3 install django。(pip3和python3安装方法请自行百度); 2、创建django项目   在linux等命令行界面下,使用django提供的命令 django-admin startproject back 注:back你的项目名。创建之后的目录结构如图红框: 可以运...

    2024-02-01 02:32:12
  • db2 export CSV文件 中文乱码解决

    若中文乱码,则在导出的语句中加入codepage参数即可,如下 db2 "export to data819.csvof del modified by codepage=1208  select * from tab1"    db2 "export to data1386.csvof del modified by codepage=1383 select * from tab1"...

    2024-02-01 02:32:06
  • 用科技号脉 九安医疗缔造数字健康生活

    用科技号脉 九安医疗缔造数字健康生活

    2013-01-16 来源: 人民网(北京)  九安医疗缔造数字健康生活&quot; style=&quot;margin:0px; padding:0px; border:0px; list-style:none&quot;&gt; 人民网·天津视窗1月16日电: 企业创新理念   与移动互联终端设备融合,打造数字化的健康生活,天津九安医疗电子股份有限公司正以数字化

    2024-02-01 02:32:01
  • 命令行工具: logcat 使用详解

    Logcat 是一个命令行工具,用于转储系统消息日志,包括设备抛出错误时的堆栈轨迹,以及从您的应用中使用Log类写入的消息。 本页面介绍了命令行 Logcat 工具,但在 Android Studio 中,您也可以从Logcat窗口查看日志消息。要了解如何在 Android Studio 中查看和过滤日志,请参阅使用 Logcat 写入和查看日志。 命令行语法 要通过 ...

    2024-02-01 02:31:53