点赞评论 加关注 不迷路
1、导入对应的jar包。
<!-- 整合redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
2、yml文件配置。
#redis配置
redis:
host: localhost
port: 6379
password: 123456
timeout: 10000ms
jedis:
pool:
max-active: 10
min-idle: 3
max-idle: 5
3、创建配置类(重要)
@Configuration
@EnableCaching
public class RedisConfiguration extends CachingConfigurerSupport {
@Bean
public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<Object,Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());//key序列化
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
4、入门案例使用;
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisDemoTest {
@Resource
private RedisTemplate<Object,Object> redisTemplate;
@Test
public void getRedis(){
//连接本地的 Redis 服务
Jedis jedis = new Jedis("localhost");
System.out.println("连接成功");
//设置 redis 字符串数据
jedis.set("str", "Hello Redis");
// 获取存储的数据并输出
System.out.println("redis 存储的字符串为: "+ jedis.get("str"));
}
@Test
public void demo(){
redisTemplate.opsForValue().set("str","Hello");
System.out.println("redis 存储的字符串为: "+ redisTemplate.opsForValue().get("str"));
}
}
spring boot在Spring Data Redis提供了两个模板:
RedisTemplate
StringRedisTemplate
RedisTemplate会使用JdkSerializationRedisSerializer处理数据,这意味着key和value都会通过Java进行序列化。
StringRedisTemplate默认会使用StringRedisSerializer处理数据。
要是操作字符串的话,用StringRedisTemplate就可以满足。但要是想要存储一个对象Object,我们就需要使用RedisTemplate,并对key采用String序列化方式,对value采用json序列化方式,这时候就需要对redisTemplate自定义配置,项目源码片段:
RedisTempalte类API
方 法 | 子API接口 | 描 述 |
opsForValue() | ValueOperations<K, V> | 操作具有简单值的条目 |
opsForList() | ListOperations<K, V> | 操作具有list值的条目 |
opsForSet() | SetOperations<K, V> | 操作具有set值的条目 |
opsForZSet() | ZSetOperations<K, V> | 操作具有ZSet值(排序的set)的条目 |
opsForHash() | HashOperations<K, HK, HV> | 操作具有hash值的条目 |
boundValueOps(K) | BoundValueOperations<K,V> | 以绑定指定key的方式,操作具有简单值的条目 |
boundListOps(K) | BoundListOperations<K,V> | 以绑定指定key的方式,操作具有list值的条目 |
boundSetOps(K) | BoundSetOperations<K,V> | 以绑定指定key的方式,操作具有set值的条目 |
boundZSet(K) | BoundZSetOperations<K,V> | 以绑定指定key的方式,操作具有ZSet值(排序的set)的条目 |
boundHashOps(K) | BoundHashOperations<K,V> | 以绑定指定key的方式,操作具有hash值的条目 |
5、spring boot缓存管理
spring boot集成redis进行数据缓存功能;有两种实现:
1,通过在代码中调用redis API实现数据的CRUD;
【参考RedisUtils工具类,该工具类支持redis的其他业务场景】
2,通过在方法上添加缓存注解实现;
【重点介绍,只支持redis作为缓存管理时使用】
Spring 提供了很多缓存管理器,例如:
SimpleCacheManager
EhCacheCacheManager
CaffeineCacheManager
GuavaCacheManager
CompositeCacheManager
RedisCacheManager Spring Data提供的缓存管理器:RedisCacheManager
在Spring Boot中通过@EnableCaching注解自动化配置合适的缓存管理器(CacheManager),默认情况下Spring Boot根据下面的顺序自动检测缓存提供者:
Generic
JCache (JSR-107)
EhCache 2.x
Hazelcast
Infinispan
Redis
Guava
Simple
因为之前已经配置了RedisTemplate了,Spring Boot就无法自动给RedisCacheManager设置RedisTemplate了,所以要自己配置CacheManager。
1, 修改RedisConfig配置类,添加@EnableCaching注解,并继承CachingConfigurerSupport,重写CacheManager 方法:
/**
* 实例化 CacheManager 对象,指定使用RedisCacheManager作缓存管理
*
* @return CacheManager
*/
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
// 设置缓存过期时间(单位:秒),60秒
rcm.setDefaultExpiration(120);
return rcm;
}
Spring提供了如下注解来声明缓存规则:
@Cacheable triggers cache population
@cacheevict triggers cache eviction
@cacheput updates the cache without interfering with the method execution
@caching regroups multiple cache operations to be applied on a method
@cacheconfig shares some common cache-related settings at class-level
注 解 | 描 述 |
@Cacheable | 表明Spring在调用方法之前,首先应该在缓存中查找方法的返回值。如果这个值能够找到,就会返回缓存的值。否则的话,这个方法就会被调用,返回值会放到缓存之中 |
@cacheput | 表明Spring应该将方法的返回值放到缓存中。在方法的调用前并不会 检查缓存,方法始终都会被调用 |
@cacheevict | 表明Spring应该在缓存中清除一个或多个条目 |
@caching | 这是一个分组的注解,能够同时应用多个其他的缓存注解 |
@cacheconfig | 可以在类层级配置一些共用的缓存配置 |
@Cacheable和@cacheput有一些共有的属性:
属 性 | 类 型 | 描 述 |
value | String[] | 要使用的缓存名称 |
condition | String | SpEL表达式,如果得到的值是false的话,不会将缓存应用到方法调用上 |
key | String | SpEL表达式,用来计算自定义的缓存key |
unless | String | SpEL表达式,如果的值得到是true的话,返回值不会放到缓存之中 |
2, 通过注解@Cacheable,对数据进行缓存处理:
代码片段:
/**
* 通过缓存注解,添加数据到redis中
* </br>实现数据缓存!
* @param cat 对象
*/
@Cacheable
@RequestMapping(value = "/getCat/{catId}", method = RequestMethod.GET)
@ResponseBody
public Cat add(@PathVariable("catId") int catId){
return this.catService.getCat(catId);
}
注意:Cat对象必须实现implements Serializable接口!
java.lang.IllegalStateException: No cache could be resolved for 'Builder[public com.wyait.redis.pojo.Cat com.wyait.redis.controller.RedisCacheController.add(int)] caches=[] | key='' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'' using resolver 'org.springframework.cache.interceptor.SimpleCacheResolver@5e67a11d'. At least one cache should be provided per cache operation. at org.springframework.cache.interceptor.CacheAspectSupport.getCaches(CacheAspectSupport.java:244) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
这个错误,是由于@Cacheable注解没有指定缓存名称导致的。加上value值,再试:
@Cacheable(value = "catCache")
测试访问成功!多次访问,走redis缓存。
3, redis缓存key生成策略
键的生成策略有两种,一种是默认策略,一种是自定义策略。
----------------------------默认策略:
If no params are given, return SimpleKey.EMPTY.
If only one param is given, return that instance.
If more the one param is given, return a SimpleKey containing all parameters.
默认的key是通过KeyGenerator生成的,其默认策略如下:
1.如果方法没有参数,则使用0作为key;
2.如果只有一个参数的话则使用该参数作为key;
3.如果参数多于一个则使用所有参数的hashcode作为key;
----------------------------自定义策略:
自定义策略是指我们通过Spring的EL表达式来指定我们的key。这里的EL表达式可以使用参数以及它们对应的属性。使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。
之前在redisTemplate里设置了template.setKeySerializer(new StringRedisSerializer()),需要key是string类型。也可以使用SpEL表达式生成Key,
(SpEL表达式:http://itmyhome.com/spring/expressions.html)
返回结果需要是string类型(比如#root.methodName就是,#root.method不是String),通用办法是重写keyGenerator定制Key默认生成策略(按照缓存名称+id方式生成key,同时确保更新操作的时候,操作的是同一条数据),也可以在使用缓存注解时指定key:
/**
* 指定key的生成策略
* @return KeyGenerator
*/
@Bean public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override public Object generate(Object target, Method method,
Object... params) {
StringBuilder sb = new StringBuilder();
String[] value = new String[1];
// sb.append(target.getClass().getName());
// sb.append(":" + method.getName());
Cacheable cacheable = method.getAnnotation(Cacheable.class);
if (cacheable != null) {
value = cacheable.value();
}
CachePut cachePut = method.getAnnotation(CachePut.class);
if (cachePut != null) {
value = cachePut.value();
}
CacheEvict cacheEvict = method.getAnnotation(CacheEvict.class);
if (cacheEvict != null) {
value = cacheEvict.value();
}
sb.append(value[0]);
//获取参数值
for (Object obj : params) {
sb.append(":" + obj.toString());
}
return sb.toString();
}
};
}
注意:
1,在使用缓存注解时,也可以指定统一规则的key
(比如:@Cacheable(value = "catCache", key = "#root.caches[0].name + ':' + #id"));
就可以不走KeyGenerator默认规则;同样可以实现,更新和查询都是同一个key的数据;
2,使用注解进行数据缓存,指定数据过期时间需要百度普及下!
4, 更新缓存数据
更新与删除Redis缓存需要用到@cacheput和@cacheevict。必须保证keyGenerator生成同一个key,否则更新的不是同一条的数据;
/**
* 更新redis中的缓存数据
*</br> #root. 是spEL表达式
* </br>如果参数是个对象,就通过“#对象.变量”获取到对应的key中需要的值;比如:#cat.id
* @param id 主键
*/
@CachePut(value = "catCache", key = "#root.caches[0].name + ':' + #id")
@RequestMapping(value = "/updateCat", method = RequestMethod.POST)
@ResponseBody
public Cat update(@RequestParam int id){
System.out.println("==========请求参数:"+id);
return this.catService.updateCat(id);