Spring-Boot项目中配置redis注解缓存
Spring-Boot项目中配置redis注解缓存
在pom中添加redis缓存支持依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
在yml中添加redis配置
设置缓存有效期为一天,配置类中使用
spring:
redis:
database: xx
host: xx.xx.xx.xx
port: 6379
password: xxxxx # 密码(默认为空)
timeout: 6000ms # 连接超时时长(毫秒)
jedis:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
activiti:
check-process-definitions: false
# spirng 缓存管理参数配置
cache:
redis:
time-to-live: 86400000
修改redis配置类
序列化缓存数据,解决乱码问题(分别配置redisTemplate和注解缓存)
@Configuration
public class RedisConfig {
@Resource
private RedisConnectionFactory factory;
@Value("${spring.cache.redis.time-to-live}")
private Duration timeToLive = Duration.ZERO;
/**
* 配置Jackson2JsonRedisSerializer序列化策略
* */
private Jackson2JsonRedisSerializer<Object> serializer() {
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
// objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return jackson2JsonRedisSerializer;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
// 配置序列化(解决乱码的问题)
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
// 缓存有效期
.entryTtl(timeToLive)
// 使用StringRedisSerializer来序列化和反序列化redis的key值
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer()))
// 禁用空值
.disableCachingNullValues();
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}
}
修改VO类,实现序列化接口
实现序列化接口才能将实体类存入缓存中
@Data
@TableName("sys_user_token")
public class SysUserTokenEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId
private Long id;
/**
* 用户ID
*/
private Long userId;
/**
* 用户token
*/
private String token;
/**
* 过期时间
*/
private Date expireDate;
/**
* 更新时间
*/
private Date updateDate;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private Date createDate;
}
注解缓存类型和用法
@Cacheable
@Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
@Cacheable(value = CACHE_KEY, key = "#id",condition = "#result != null")
public Tasklog findById(String id){
return taskLogMapper.selectById(id);
}
| 参数 | 解释 | example |
|---|---|---|
| value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | 例如: @Cacheable(value=”mycache”) @Cacheable(value={”cache1”,”cache2”} |
| key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | @Cacheable(value=”testcache”,key=”#userName”) |
| condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 | @Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
@CachePut
@CachePut 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用
@CachePut(value = CACHE_KEY, key = "#tasklog.id")
public Tasklog create(Tasklog tasklog){
taskLogMapper.insert(tasklog);
return tasklog;
}
| 参数 | 解释 | example |
|---|---|---|
| value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | @CachePut(value=”my cache”) |
| key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | @CachePut(value=”testcache”,key=”#userName”) |
| condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 | @CachePut(value=”testcache”,condition=”#userName.length()>2”) |
@CacheEvict
@CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空
@CacheEvict(value = CACHE_KEY, key = "#id")
public void delete(String id){
taskLogMapper.deleteById(id);
}
| 参数 | 解释 | example |
|---|---|---|
| value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | @CacheEvict(value=”my cache”) |
| key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | @CacheEvict(value=”testcache”,key=”#userName”) |
| condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 | @CacheEvict(value=”testcache”,condition=”#userName.length()>2”) |
| allEntries | 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 | @CachEvict(value=”testcache”,allEntries=true) |
| beforeInvocation | 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 | @CachEvict(value=”testcache”,beforeInvocation=true) |
在项目启动类中上添加@EnableCaching注解,表明启用缓存功能。
@SpringBootApplication
@EnableCaching
public class Ch06CacheApplication {
public static void main(String[] args) {SpringApplication.run(Ch06CacheApplication.class, args);}
}
注意:设置注解缓存不生效的情形
情形一:
@CachePut注解须加在有返回值的方法上
有些service的实现类中,由于框架的限制,其父类的更新方法是没有返回值的。例如下面的方法中,虽然可以拿到key值,但注解缓存是根据方法的返回值进行更新的,所以会造成数据库更新了数据而缓存中的数据并没有更新。
@Override
@Transactional(rollbackFor = Exception.class)
@CachePut(value = Constant.UserCacheConstant.USERIDCACHE,key="#dto.id")
public void update(WarningRuleDTO dto) {
super.update(dto);
}
情形二:
加的注解缓存的方法必须是spring通过反射调用的,方法间的调用不会生效。
由于Controller通过反射调用的update方法,继而在调用update2方法,此时缓存注解也是无法生效的。
@Override
@Transactional(rollbackFor = Exception.class)
public void update(WarningRuleDTO dto) {
update2();
}
@CachePut(value = Constant.UserCacheConstant.USERIDCACHE,key="#dto.id")
private WarningRuleDTO update2(WarningRuleDTO dto){
super.update(dto);
}
解决方法
既然没办法进行更新操作,那就根据value删除对应的所有key值
@Override
@Transactional(rollbackFor = Exception.class)
@CacheEvict(value = Constant.UserCacheConstant.USERIDCACHE,allEntries = true)
public void update(WarningRuleDTO dto) {
super.update(dto);
}
Spring-Boot项目中配置redis注解缓存的更多相关文章
- Spring Boot项目中使用Mockito
本文首发于个人网站:Spring Boot项目中使用Mockito Spring Boot可以和大部分流行的测试框架协同工作:通过Spring JUnit创建单元测试:生成测试数据初始化数据库用于测试 ...
- 在Spring Boot项目中使用Spock测试框架
本文首发于个人网站:在Spring Boot项目中使用Spock测试框架 Spock框架是基于Groovy语言的测试框架,Groovy与Java具备良好的互操作性,因此可以在Spring Boot项目 ...
- Spring Boot项目中如何定制拦截器
本文首发于个人网站:Spring Boot项目中如何定制拦截器 Servlet 过滤器属于Servlet API,和Spring关系不大.除了使用过滤器包装web请求,Spring MVC还提供Han ...
- Spring Boot项目中如何定制PropertyEditors
本文首发于个人网站:Spring Boot项目中如何定制PropertyEditors 在Spring Boot: 定制HTTP消息转换器一文中我们学习了如何配置消息转换器用于HTTP请求和响应数据, ...
- Spring Boot项目中如何定制servlet-filters
本文首发于个人网站:Spring Boot项目中如何定制servlet-filters 在实际的web应用程序中,经常需要在请求(request)外面增加包装用于:记录调用日志.排除有XSS威胁的字符 ...
- Spring Boot项目中使用Swagger2
Swagger2是一款restful接口文档在线生成和在线接口调试工具,Swagger2在Swagger1.x版本的基础上做了些改进,下面是在一个Spring Boot项目中引入Swagger2的简要 ...
- 你真的理解 Spring Boot 项目中的 parent 吗?
前面和大伙聊了 Spring Boot 项目的三种创建方式,这三种创建方式,无论是哪一种,创建成功后,pom.xml 坐标文件中都有如下一段引用: <parent> <groupId ...
- 在Spring Boot项目中使用Spock框架
转载:https://www.jianshu.com/p/f1e354d382cd Spock框架是基于Groovy语言的测试框架,Groovy与Java具备良好的互操作性,因此可以在Spring B ...
- Spring Boot2 系列教程(三)理解 Spring Boot 项目中的 parent
前面和大伙聊了 Spring Boot 项目的三种创建方式,这三种创建方式,无论是哪一种,创建成功后,pom.xml 坐标文件中都有如下一段引用: <parent> <groupId ...
随机推荐
- Serializable使用
android的另一个序列化Serializable比较简单,实现它的接口,然后生成所有成员变量的方法,再生成所有成员变量的getset方法,serializable可以存储对象,所以下面代码传递了一 ...
- 如何在 vue 项目里正确地引用 jquery
转载 2016年11月13日 使用vue-cli构建的vue项目,webpack的配置文件是分散在很多地方的,而我们需要修改的是build/webpack.base.conf.js,修改两处的代码 / ...
- python接口自动化测试遇到的问题及解决方案
工作中xml中的某一个字段是全网唯一,这就需要进行参数化处理.此次对这一个字段进行参数化处理引用了random模块和index()函数.代码如下: #!/usr/bin/python # -*- co ...
- eclipse之SSH配置hibernate【三】
配置hibernate,没有和spring整合,可以看成独立的部分. 在src下创建hibernate配置文件,hibernate.cfg.xml.主要是sql连接相关配置. <?xml ver ...
- js——事件循环
JS-事件循环 js运行的环境称之为宿主环境. 执行栈 :call stack ,一个数据结构,用于存放各种函数的执行环境,每一个函数执行之前他的相关信息会加入到执行栈中,函数调用之前,创建执行环境, ...
- numpy数组
一.数组创建 基础数组 1.array() array函数可以创建一维或多维数 一维数组 1.arange(起始值,终值,步长) 2.linspace(起始值,终值,元素个数) --创建等步长的数组 ...
- 【Android Studio】安卓开发初体验3.1——UI设计之常用控件
常用控件 首先对xml文件的编辑有三种模式 Code为纯代码 Split是一边代码,一边预览效果图 Designer就是有UI设计界面 TextView 用于在界面上显示一段文本信息 所有控件都可以在 ...
- 微信小程序开发之云开发
创建云开发小程序项目 开通云开发 开通后界面 选择开发环境 开启使用npm模块 安装wx-server-sdk npm install --save wx-server-sdk@latest 创建云函 ...
- 使用switch计算出某年某月某日是今年的第几天,输出一直是当月天数
package com.cx.Switch; import java.util.Scanner; /** * 计算出某年某月某日是今年的第几天 * 使用switch */ public class S ...
- 案例:简易的Div拖拽
案例:简易的Div拖拽 鼠标移入Div区域后,按下鼠标左键,可以拖动Div移动;松开鼠标左键,Div拖动停止.同时要求Div不能拖出屏幕显示区域外. 拖拽原理:距离不变.三个事件(onmousedow ...