SpringBoot Redis缓存 @Cacheable、@CacheEvict、@CachePut
- 文章来源 https://blog.csdn.net/u010588262/article/details/81003493
1. pom.xml
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
2. Springboot配置文件
- spring.redis.host=127.0.0.1
- spring.redis.port=6379
- spring.redis.database=5
- spring.redis.password=123456
- # 连接超时时间 单位 ms(毫秒)
- spring.redis.timeout=3000
- #=========redis线程池设置=========
- # 连接池中的最大空闲连接,默认值也是8。
- spring.redis.pool.max-idle=10
- #连接池中的最小空闲连接,默认值也是0。
- spring.redis.pool.min-idle=0
- # 如果赋值为-1,则表示不限制;pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
- spring.redis.pool.max-active=10
- # 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时
- spring.redis.pool.max-wait=1000
3. Redis配置文件
- import com.fasterxml.jackson.annotation.JsonAutoDetect;
- import com.fasterxml.jackson.annotation.PropertyAccessor;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import org.springframework.cache.CacheManager;
- import org.springframework.cache.annotation.CachingConfigurerSupport;
- import org.springframework.cache.annotation.EnableCaching;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.data.redis.cache.RedisCacheConfiguration;
- import org.springframework.data.redis.cache.RedisCacheManager;
- import org.springframework.data.redis.connection.RedisConnectionFactory;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.data.redis.core.StringRedisTemplate;
- import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
- import org.springframework.data.redis.serializer.RedisSerializer;
- import org.springframework.data.redis.serializer.StringRedisSerializer;
- import java.time.Duration;
- /**
- * @Auther: hugeo.wang
- * @Date: 2018/7/11 11:07
- * @Description:
- */
- @Configuration
- @EnableCaching
- public class RedisConfig extends CachingConfigurerSupport {
- @Bean
- public CacheManager cacheManager(RedisConnectionFactory factory) {
- RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
- .entryTtl(Duration.ofSeconds(60))
- .disableCachingNullValues();
- return RedisCacheManager.builder(factory)
- .cacheDefaults(config)
- .transactionAware()
- .build();
- }
- @Bean
- public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
- StringRedisTemplate template = new StringRedisTemplate(factory);
- RedisSerializer keySerializer = new StringRedisSerializer(); // 设置key序列化类,否则key前面会多了一些乱码
- template.setKeySerializer(keySerializer);
- setValueSerializer(template);//设置value序列化
- template.afterPropertiesSet();
- template.setEnableTransactionSupport(true);
- return template;
- }
- private void setValueSerializer(StringRedisTemplate template) {
- @SuppressWarnings({"rawtypes", "unchecked"})
- Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
- ObjectMapper om = new ObjectMapper();
- om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
- om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
- jackson2JsonRedisSerializer.setObjectMapper(om);
- template.setValueSerializer(jackson2JsonRedisSerializer);
- }
- }
4. 使用三个注解开始玩耍
@Cacheable
@Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。
如果一个方法上添加了@Cacheable标记,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。
缓存是以键值对进行的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略,需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。
@Cacheable可以指定三个属性,value、key和condition。
- value 指定Cache名称
value
必须指定,表示当前方法的返回值会被缓存在哪个Cache上,对应Cache的名称。可以是一个Cache也可以是多个Cache,当需要指定多个Cache时其是一个数组。
- @Cacheable("cache1")//Cache是发生在cache1上的
- public User find(Integer id) {
- return null;
- }
- @Cacheable({"cache1", "cache2"})//Cache是发生在cache1和cache2上的
- public User find(Integer id) {
- return null;
- }
- key 自定义缓存的键
用来指定Spring缓存时对应的key的。该属性支持SpringEL表达式。当我们没有指定该属性时,Spring将使用默认策略生成key。
自定义策略是指我们可以通过Spring的EL表达式来指定我们的key。这里的EL表达式可以使用方法参数及它们对应的属性。使用方法参数时我们可以直接使用#参数名或者#p参数index。下面是几个使用参数作为key的示例。
- // 如果要用固定字符串加上参数的属性记得加单引号
- @Cacheable(value="users", key="'helloworld'+#p0.id")
- public User find(User user) {
- return null;
- }
- @Cacheable(value="users", key="#id")
- public User find(Integer id) {
- return null;
- }
- @Cacheable(value="users", key="#p0")
- public User find(Integer id) {
- return null;
- }
- @Cacheable(value="users", key="#user.id")
- public User find(User user) {
- return null;
- }
- @Cacheable(value="users", key="#p0.id")
- public User find(User user) {
- return null;
- }
除了上述使用方法参数作为key之外,Spring还为我们提供了一个root对象可以用来生成key。通过该root对象我们可以获取到以下信息。
属性名称 | 描述 | 示例 |
methodName | 当前方法名 | root.methodName |
method | 当前方法 | root.method.name |
target | 当前被调用的对象 | root.target |
targetClass | 当前被调用的对象的 | class root.targetClass |
args | 当前方法参数组成的数组 | root.args[0] |
caches | 当前被调用的方法使用的 | Cache root.caches[0].name |
当我们要使用root对象的属性作为key时我们也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。如:
- @Cacheable(value={"users", "xxx"}, key="caches[1].name")
- public User find(User user) {
- return null;
- }
有的时候我们可能并不希望缓存一个方法所有的返回结果。通过condition属性可以实现这一功能。condition属性默认为空,表示将缓存所有的调用情形。其值是通过SpringEL表达式来指定的,当为true时表示进行缓存处理;当为false时表示不进行缓存处理,即每次调用该方法时该方法都会执行一次判断。如下示例表示只有当user的id为偶数时才会进行缓存。
- @Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0")
- public User find(User user) {
- System.out.println("find user by user " + user);
- return user;
- }
@CacheEvict
这个@CacheConfig注解用来清除缓存,在注解里指定cachename,key和condition,spring会把符合这三个要求的缓存删除掉
总共有5个属性:value,key,condition,allentries,beforeInvocation
前三个注解不说了
allentries
缺省为false,将这个属性设置为true的话就不用设置key了,会删除value指定的cachename下所有的缓存
beforeInvocation
缺省为false,默认spring是会在调用方法成功之后清除缓存的,如果方法里面抛错了自然也就不清除了,但是把此值设置为true的话spring会在调用方法前就删除缓存,也就是说不管方法执行结果如何缓存都删。
- @CacheEvict(value="accountCache",key="#account.getName()")// 清空accountCache 缓存
- public void updateAccount(Account account) {
- updateDB(account);
- }
- @CacheEvict(value="accountCache",allEntries=true)// 清空accountCache 缓存
- public void reload() {
- reloadAll()
- }
@CachePut
这个注解容易与@Cacheable搞混,对于@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。
@CachePut也可以声明一个方法支持缓存功能。不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
- @CachePut("users")//每次都会执行方法,并将结果存入指定的缓存中
- public User find(Integer id) {
- return null;
- }
@CacheConfig
这是一个类级别的注解,比如一个类里所有的缓存都是放在cachename为books
的缓存中,那么每个@Cacheable中都要写value=”books”,现在有个更方便的方法了
- @CacheConfig(value="books")
- public class BookRepositoryImpl implements BookRepository {
- @Cacheable(key="'book'")
- public Book findBook(ISBN isbn) {...}
- }
@Caching
有时候我们可能组合多个Cache注解使用;比如用户新增成功后,我们要添加id–>user;username—>user;email—>user的缓存;此时就需要@Caching组合多个注解标签了。
- @Caching(put = {
- @CachePut(value = "user", key = "#user.id"),
- @CachePut(value = "user", key = "#user.username"),
- @CachePut(value = "user", key = "#user.email")
- })
- public User save(User user) {}
自定义缓存注解
刚刚那个@Caching组合,会让方法上的注解显得整个代码比较乱,此时可以使用自定义注解把这些注解组合到一个注解中,如:
- @Caching(put = {
- @CachePut(value = "user", key = "#user.id"),
- @CachePut(value = "user", key = "#user.username"),
- @CachePut(value = "user", key = "#user.email")
- })
- @Target({ElementType.METHOD, ElementType.TYPE})
- @Retention(RetentionPolicy.RUNTIME)
- @Inherited
- public @interface UserSaveCache {
- }
这样我们在方法上使用如下代码即可,整个代码显得比较干净。
- @UserSaveCache
- public User save(User user)
综合实例
- //@Cacheable 在执行方法之前判断condition,如果返回true,则查缓存;
- @Cacheable(value = "user", key = "#id", condition = "#id lt 10")
- public User conditionFindById(final Long id) {}
- //@CachePut 在执行完方法后判断condition,如果返回true,则放入缓存;
- @CachePut(value = "user", key = "#id", condition = "#result.username ne 'zhang'")
- public User conditionSave(final User user) {}
- //@CachePut将在执行完方法后判断unless,如果返回false,则放入缓存;(即跟condition相反)
- @CachePut(value = "user", key = "#user.id", unless = "#result.username eq 'zhang'")
- public User conditionSave2(final User user) {}
- //@CacheEvict, beforeInvocation=false表示在方法执行之后调用,判断condition,如果返回true,则移除缓存;
- @CacheEvict(value = "user", key = "#user.id", beforeInvocation = false, condition = "#result.username ne 'zhang'")
- public User conditionDelete(final User user) {}
SpringBoot Redis缓存 @Cacheable、@CacheEvict、@CachePut的更多相关文章
- SpringBoot进阶教程(二十五)整合Redis之@Cacheable、@CachePut、@CacheEvict的应用
在上一篇文章(<SpringBoot(二十四)整合Redis>)中,已经实现了Spring Boot对Redis的整合,既然已经讲到Cache了,今天就介绍介绍缓存注解.各家互联网产品现在 ...
- SpringBoot 整合缓存Cacheable实战详细使用
前言 我知道在接口api项目中,频繁的调用接口获取数据,查询数据库是非常耗费资源的,于是就有了缓存技术,可以把一些不常更新,或者经常使用的数据,缓存起来,然后下次再请求时候,就直接从缓存中获取,不需要 ...
- springboot redis 缓存对象
只要加入spring-boot-starter-data-redis , springboot 会自动识别并使用redis作为缓存容器,使用方式如下 gradle加入依赖 compile(" ...
- springboot Redis 缓存
1,先整合 redis 和 mybatis 步骤一: springboot 整合 redis 步骤二: springboot 整合 mybatis 2,启动类添加 @EnableCaching 注解, ...
- springboot + redis缓存使用
[参照资料] 1.spring boot 官网文档 2.https://www.cnblogs.com/gdpuzxs/p/7222309.html [项目结构] [pom.xml配置] <?x ...
- 微服务-Springboot+Redis缓存管理接口代码实现
废话少说,上代码,结合代码讲解: 一.创建maven工程:导入依赖: <packaging>war</packaging><!--修改jdk的版本--><pr ...
- 从.Net到Java学习第七篇——SpringBoot Redis 缓存穿透
从.Net到Java学习系列目录 场景描述:我们在项目中使用缓存通常都是先检查缓存中是否存在,如果存在直接返回缓存内容,如果不存在就直接查询数据库然后再缓存查询结果返回.这个时候如果我们查询的某一个数 ...
- springboot redis 缓存跨域丢失问题
对于前后端分离的项目,在开发阶段经常会遇到跨域的问题. 1.首先,对于后台的处理方式,第一种是用 @CrossOrigin 注解,@crossorigin是后端SpringMVC框架(需4.2版本以上 ...
- SpringBoot学习笔记(6) SpringBoot数据缓存Cache [Guava和Redis实现]
https://blog.csdn.net/a67474506/article/details/52608855 Spring定义了org.springframework.cache.CacheMan ...
随机推荐
- [转帖]SAP BASIS日常需要做的工作
SAP BASIS日常需要做的工作 https://www.cnblogs.com/swordxia/p/4790684.html SAP Basis的一些日常工作包括用户权限管理.集团管理.数据库管 ...
- vertical-align和text-align属性实现垂直水平居中
HTML: <div class="box"> <div class="content"> <span class="s ...
- Shell命令-文件压缩解压缩之gzip、zip
文件及内容处理 - gzip.zip 1.gzip:gzip压缩工具 gzip命令的功能说明 gzip 命令用于压缩文件.gzip 是个使用广泛的压缩程序,文件经它压缩过后,其名称后面会多出 .gz ...
- Python——Django-form表单提交
一.提交的注意事项 1. form不是from,所有获取用户输入的标签都应该放在form里面, input并且必须要有name属性 2. action属性控制往哪儿提交,method一般都设置成pos ...
- Bugku 杂项 啊哒
有趣的表情包来源:第七届山东省大学生网络安全技能大赛 下载下来安装包后可以得到一张图片,010发现jpg后面还夹带着一些东西,用binwalk提取后得到一个压缩包,但是需要密码. 我卡在这里了,尝试了 ...
- python之模块、包的导入过程和开发规范
摘要:导入模块.导入包.编程规范 以My_module为例,My_module的代码如下: __all__ = ['name','read'] print('in mymodule') name = ...
- 进程间通信(队列、管道)、消费者模型和进程池(apply,apply_async,map)
一.队列(先进先出) 进程间通信:IPC(Inter-Process Communication) 队列是使用管道和锁定实现,所以Queue是多进程安全的队列,使用Queue可以实现多进程之间的数据传 ...
- Linux下python3、virtualenv、Mysql、redis安装配置
一.在Linux安装python解释器 1.下载python3源码包 cd /opt/ wget https://www.python.org/ftp/python/3.6.2/Python-3.6. ...
- Windows + Ubuntu 16.04 双系统安装详细教程
Windows + Ubuntu 16.04 双系统安装详细教程 2018年01月28日 16:43:19 flyyufenfei 阅读数:165619 发现了一篇好教程,果断转载了,以后用得着时 ...
- bzoj 3223: Tyvj 1729 文艺平衡树 (splay)
链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3223 题面: 3223: Tyvj 1729 文艺平衡树 Time Limit: 10 S ...