springboot启用redis缓存
1、加入maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
2、添加配置文件
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0
3、添加 cache 的配置类
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
}
5、自动根据方法生成缓存
//@Cacheable的value参数实际上就是hset命令的key字段
//@Cacheable的key参数是hset的field字段,
//最后@Cacheable注解所在的函数返回值是hset命令的value字段
@RestController
public class UserController {
@RequestMapping("/getUser")
@Cacheable(value="user-key")
public User getUser() {
User user=new User("aa@126.com", "aa", "aa123456", "aa","123");
System.out.println("若下面没出现“无缓存的时候调用”字样且能打印出数据表示测试成功");
return user;
}
}
//也可以自己指定hash的field字段
@GetMapping("page")
@Cacheable(value="report-week", key = "#params.get(\"department_id\")+'-'+#params.get(\"date_type\")+'-'+#params.get(\"target_id\")+'-'" +
"+#params.get(\"search_type\")+'-'+#params.get(\"page\")+'-'+#params.get(\"limit\")+'-'+#params.get(\"order\")+'-'+#params.get(\"export\")" +
"+'-'+#params.get(\"statistic_type\")+'-'+#params.get(\"date_time\")")
public Result<PageData<TrainReportWeekDTO>> page(@ApiIgnore @RequestParam Map<String, Object> params, HttpServletResponse response) {
。。。
}
//也可以自己指定缓存条件
@Cacheable(value = "UnitStatistical", key = "#unitStatisticalPayload.disasterId"+"-"+"#unitStatisticalPayload.type", condition="'5150'.equals(#unitStatisticalPayload.disasterId)")
6、使用@CacheEvict清除缓存
//@CacheEvict在方法上使用,默认方法成功执行完后调用,失败不调用,使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素
@CacheEvict(value="report-week", beforeInvocation=true)
public void deleteUserById(Integer id) {
//在这里执行删除操作, 删除是去数据库中删除
}
//有时候@CacheEvict不起作用,需要添加参数allEntries = true,指定Cache清除该value的所有的元素
@CacheEvict(value="report-week", allEntries = true)
public void deleteUserById(Integer id) {
//在这里执行删除操作, 删除是去数据库中删除
}
//一个方式同时删除多条条目
@Caching(evict = {
@CacheEvict(value = "report-week", allEntries = true),
@CacheEvict(value = "report-month", allEntries = true),
@CacheEvict(value = "report-year", allEntries = true),
@CacheEvict(value = "report-halfweek", allEntries = true)
})
public void deleteUserById(Integer id) {
//在这里执行删除操作, 删除是去数据库中删除
}
7、使用@CachePut更新缓存
//这个注解一般加在更新方法上,当数据库中的数据更新后,缓存中的数据也要跟着更新,使用该注解,可以将方法的返回值自动更新到已经存在的key上,示例代码如下:
@CachePut(key = "#user.id")
public User updateUserById(User user) {
return user;
}
7、分部署系统中使用session共享解决缓存公用的问题
#参考
http://www.ityouknow.com/springboot/2016/03/06/spring-boot-redis.html
8、 使用方法参数作为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对象的属性
如果要调用当前类里面的方法:
@Override
@Cacheable(value={"TeacherAnalysis_public_chart"}, key="#root.target.getDictTableName() + '_' + #root.target.getFieldName()")
public List<Map<String, Object>> getChartList(Map<String, Object> paramMap) {
}
public String getDictTableName(){
return "";
}
public String getFieldName(){
return "";
9、在使用@Cacheable
注解对查询数据进行缓存时,使用cacheNames
属性指定了缓存名称。下面我们就针对不同的cacheNames
来设置失效时间
添加Redis
配置类RedisConfig.java
,代码如下:
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{
/**
* 自定义缓存管理器
*/
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
Set<String> cacheNames = new HashSet<>();
cacheNames.add("car");
cacheNames.add("distributor");
ConcurrentHashMap<String, RedisCacheConfiguration> configMap = new ConcurrentHashMap<>();
configMap.put("car", config.entryTtl(Duration.ofMinutes(6L)));
configMap.put("distributor", config);
//需要先初始化缓存名称,再初始化其它的配置。
RedisCacheManager cacheManager = RedisCacheManager.builder(factory).initialCacheNames(cacheNames).withInitialCacheConfigurations(configMap).build();
return cacheManager;
}
}
RedisConfig.java
中加入value序列化:
@Configuration
@EnableCaching
public class MyRedisConfig extends CachingConfigurerSupport {
/**
* 自定义缓存管理器
*/
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
//value 序列化
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer))
.disableCachingNullValues();
Set<String> cacheNames = new HashSet<>();
cacheNames.add("report-week");
ConcurrentHashMap<String, RedisCacheConfiguration> configMap = new ConcurrentHashMap<>();
configMap.put("report-week", config.entryTtl(Duration.ofHours(1L)));
//需要先初始化缓存名称,再初始化其它的配置。
RedisCacheManager cacheManager = RedisCacheManager.builder(factory).initialCacheNames(cacheNames).withInitialCacheConfigurations(configMap).cacheDefaults(config).build();
return cacheManager;
}
}
**注意:**JacksonJsonRedisSerializer和GenericJackson2JsonRedisSerializer,两者都能系列化成json,但是后者会在json中加入@class属性,类的全路径包名,方便反系列化(json—>user对象过程)。前者如果存放了List则在反系列化的时候如果没指定TypeReference则会报错java.util.LinkedHashMap cannot be cast to
如果报错Could not read JSON: Cannot construct instance of’'类名""(no Creators, like default construct, exist),是因为redis的这些序列化方式,使用的是无参构造函数进行创建对象set方法进行赋值,方法中存在有参的构造函数,默认存在的无参构造函数是不存在的(继承自object),必须显示的去重写,在实体类中加入@NoArgsConstructor