文章目录
springboot默认使用Simple缓存组件进行缓存管理,Simple组件位于9大缓存组件最后一个(按顺序启用),所以,当没有其他缓存组件引入时,就使用Simple缓存组件,即springboot默认提供的缓存组件
缓存的作用:减少系统查询时间,执行查询时,会先从缓存中查询数据,如果缓存中没有,再去数据库中查询,然后把查询到的数据放到缓存中。(更新操作,会先删除缓存,再存入缓存;删除操作,删除缓存)
一、使用springboot默认的缓存管理
在启动类上加上@EnableCaching ,代表开启Spring Boot基于注解的缓存管理支持
@EnableCaching //开启Spring Boot基于注解的缓存管理支持
@SpringBootApplication
public class CacheApplication {
public static void main(String[] args) {
SpringApplication.run(CacheApplication.class, args);
}
}
所有缓存注解使用都在Service层下
缓存的注解:
@EnableCaching:开关性注解,在项目启动类或某个配置类上使用此注解后,则表示允许使用注解的方式进行缓存操作
@Cacheable:可用于类或方法上;在目标方法执行前,会根据key先去缓存中查询看是否有数据,有就直接
返回缓存中的key对应的value值。不再执行目标方法;无则执行目标方法,并将方法的返回值
作为value,并以键值对的形式存入缓存
**@CachePut:**可用于类或方法上;在执行完目标方法后,并将方法的返回值作为value,并以键值对的形式存入缓存中
**@CacheEvict:**可用于类或方法上;在执行完目标方法后,清除缓存中对应key的数据(如果缓存
中有对应key的数据缓存的话)
**@Caching:**此注解即可作为@Cacheable、@CacheEvict、@CachePut三种注解中的的任何一种或几种来使用
@CacheConfig:@Cacheable、@CacheEvict、@CachePut这三个注解的cacheNames属性是必
填项(或value属性是必填项,因为value属性是cacheNames的别名属性);如果上述
三种注解都用的是同一个cacheNames的话,那么在每此都写cacheNames的话,
就会显得麻烦。如将@CacheConfig注解就是来配置一些公共属性(如:cacheNames、
keyGenerator等)的值的
缓存注解的常用属性
cacheNames/values:指定缓存组件的名字,将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存
key:缓存数据的标识。默认是使用方法参数的值
condition:指定符合条件的情况下才缓存; 如:condition = “#a0>1” 即第一个参数值大于1时才进行缓存
unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到的结果进行判断
如: unless = “#a0”:如果第一个参数值是2,则结果不缓存
unless = “#result == null” 结果为null不缓存
@Service
public class CommentService {
@Autowired
private CommentRepository commentRepository;
// 根据评论id查询评论信息
// @Cacheable(cacheNames = "comment")
@Cacheable(cacheNames = "comment",unless = "#result==null")
public Comment findById(int comment_id){
Optional<Comment> optional = commentRepository.findById(comment_id);
if(optional.isPresent()){
return optional.get();
}
return null;
}
// 更新评论信息
@CachePut(cacheNames = "comment",key = "#result.id")
public Comment updateComment(Comment comment){
commentRepository.updateComment(comment.getAuthor(), comment.getaId());
return comment;
}
// 删除评论信息
@CacheEvict(cacheNames = "comment")
public void deleteComment(int comment_id){
commentRepository.deleteById(comment_id);
}
}
二、springboot整合Redis缓存实现
引入Redis的启动依赖,引入redis依赖后,就代表引入了Redis缓存组件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
在配置文件中配置Redis
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
1.基于注解的Redis缓存实现
在上文中使用Springboot默认的Simple组件的基础上,让实体类序列化就可以了(让实体类实现Serializable接口)。
2.基于API的Redis缓存实现
在service中使用@Autowired注解注入Redis API中常用的RedisTemplate
@Service
public class ApiCommentService {
@Autowired
private CommentRepository commentRepository;
@Autowired
private RedisTemplate redisTemplate;
public Comment findById(int comment_id){
// 先从Redis缓存中查询数据
Object object = redisTemplate.opsForValue().get("comment_"+comment_id);
if (object!=null){
return (Comment)object;
}else {
// 缓存中没有,就进入数据库查询
Optional<Comment> optional = commentRepository.findById(comment_id);
if(optional.isPresent()){
Comment comment= optional.get();
// 将查询结果进行缓存,并设置有效期为1天
redisTemplate.opsForValue().set("comment_"+comment_id, comment,1, TimeUnit.DAYS);
return comment;
}else {
return null;
}
}
}
}
RedisTemplate内部使用的序列化方式要求被序列化的实体类继承Serializable接口,实现序列化
注:
- 基于API的Redis缓存实现不需要@EnableCaching注解开启基于注解的缓存支持。
- 基于API的Redis缓存实现需要在Spring Boot项目的pom.xml文件中引入Redis依赖启动器,并在配置文件中进行Redis服务连接配置,同时将进行数据存储的Comment实体类实现序列化接口。
- 缓存测试与基于注解的Redis缓存实现的测试完全一样。
在项目中引入Redis依赖后,Springboot提供的RedisAutoConfiguration自动配置生效,使用默认提供的序列化方式
如果想使用自定义的序列化方式,需要自定义一个配置类,创建一个名为redisTemplate的Bean组件。
@Configuration // 定义一个配置类
public class RedisConfig {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
// 使用JSON格式序列化对象,对缓存数据key和value进行转换
Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
// 解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// 设置RedisTemplate模板API的序列化方式为JSON
template.setDefaultSerializer(jacksonSeial);
return template;
}
}
自定义RedisCacheManager缓存管理器的默认序列化机制
Spring Boot整合Redis组件提供的缓存自动配置类RedisCacheConfiguration,其内部是通过Redis连接工厂RedisConnectionFactory定义了一个缓存管理器RedisCacheManager;同时定制RedisCacheManager时,也默认使用了JdkSerializationRedisSerializer序列化方式。
Springboot1.x版本中,RedisCacheManager是在RedisTemplate的基础上进行构建的,而Springboot2.x版本中,RedisCacheManager是单独进行构建的。因此,Springboot2.x版本中,对RedisTemplate进行自定义序列化机制构建后,仍然无法对RedisCacheManager内部默认序列化机制进行覆盖,也就解释了基于注解的Redis缓存实现仍然会使用JDK默认序列化机制的原因,想要基于注解的Redis缓存也使用自定义序列化机制,需要自定义RedisCacheManager
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
// 分别创建String和JSON格式序列化对象,对缓存数据key和value进行转换
RedisSerializer<String> strSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jacksonSeial =
new Jackson2JsonRedisSerializer(Object.class);
// 解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// 定制缓存数据序列化方式及时效
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(1))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(strSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSeial))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).build();
return cacheManager;
}