SpringBoot整合Redis之使⽤@Cacheable注解@Cacheable实现⾃动缓存,属性为value、key和condition:
参数作⽤
value缓存的名称
key缓存的 key, SpEL 表达式condition缓存的条件
本⽂环境为SpringBoot2.X,以下为使⽤过程及个⼈理解:
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
SpringBoot2.X使⽤lettuce,但是个⼈习惯加上其他原因所以换成了jedis。
配置⽂件配置
redis:cacheable
port: 6379
jedis:
pool:
max-active: 500
max-wait: 50000
max-idle: 500
min-idle: 0
timeout: 50000
host: www.baidu
cache:
type: redis #缓存类型
redis:
cache-null-values: false #不缓存null数据
time-to-live: 50000ms #超时时间
use-key-prefix: false #不使⽤前缀
host换成你⾃⼰的IP即可
配置⽂件设置(敲⿊板)
RedisConstant.java
public class RedisConstant {
/**
* 数据⾃增步长为1
*/
public static final Integer INCREMENT =1;
/**
* 数据⾃减步长为1
*/
public static final Integer REDUCTION =-1;
/**
* 存储⽤户信息前缀
*/
public static final String USER ="user:";
}
鉴于篇幅,此处只放USER⼀个常量,这个常量类的作⽤:全局使⽤,⼀改全改,注意,如果你不想⿇烦就⼀定要将USER常量的:留着,对于后续操作缓存提供了太多的⽅便!!
RedisConfig.java
配置类,⼤⽤!即使不使⽤@Cacheable这个类也该有
fig;
import java.sql.SQLException;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
stant.RedisConstant;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import t.annotation.Bean;
import t.annotation.Configuration;
import org.dis.cache.RedisCacheConfiguration;
import org.dis.cache.RedisCacheManager;
import org.dis.cache.RedisCacheWriter;
import org.tion.RedisConnectionFactory;
import org.RedisTemplate;
import org.dis.serializer.Jackson2JsonRedisSerializer;
import org.dis.serializer.RedisSerializationContext;
import org.dis.serializer.StringRedisSerializer;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import ansaction.PlatformTransactionManager;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* 缓存Redis配置
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* 使⽤Jackson2JsonRedisSerialize 替换默认序列化
*/
@Bean
public RedisTemplate<Object, Object>redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<Object, Object> redisTemplate =new RedisTemplate<>();
// 使⽤Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =new Jackson2JsonRedisSerializer<Object>(
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =new Jackson2JsonRedisSerializ
er<Object>(
Object.class);
ObjectMapper objectMapper =new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// hash参数序列化⽅式
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
// 缓存⽀持回滚(事务管理)
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
// 配置事务管理器
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource)throws SQLException {
return new DataSourceTransactionManager(dataSource);
}
/**
* 配置⾃动化缓存使⽤的序列化⽅式以及过期时间
*/
@Bean
public RedisCacheConfiguration redisCacheConfiguration(){
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =new Jackson2JsonRedisSerializer<Object>(
Object.class);
ObjectMapper objectMapper =new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
configuration = configuration
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.entryTtl(Duration.ofDays(1));
return configuration;
}
/**
* 缓存过期时间⾃定义配置
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){
// 设置CacheManager的值序列化⽅式为Jackson2JsonRedisSerializer,默认就是使⽤StringRedisSerializer序列化key,JdkSerializationRedisSerializer序列化value
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =new Jackson2JsonRedisSerializer<Object>(
Object.class);
ObjectMapper objectMapper =new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 配置value序列化⽅式为Jackson2JsonRedisSerializer,key序列化⽅式采⽤默认的StringRedisSerializer
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));
// 每⼀类信息进⾏缓存配置
Map<String, RedisCacheConfiguration> redisCacheConfigurationMap =new HashMap<>();
// ⽤户信息
redisCacheConfigurationMap.put(RedisConstant.USER, Ttl(Duration.ofDays(10))
.disableCachingNullValues().prefixKeysWith(RedisConstant.USER));
// 初始化⼀个RedisCacheWriter
RedisCacheWriter redisCacheWriter = LockingRedisCacheWriter(redisConnectionFactory);
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));
// 设置默认超过期时间是1天(短时间的已经做了其他的处理,不会采⽤注解形式加⼊缓存)
// 初始化RedisCacheManager
RedisCacheManager cacheManager =new RedisCacheManager(redisCacheWriter, defaultCacheConfig,
redisCacheConfigurationMap);
return cacheManager;
}
}
嗯,redisCacheConfiguration是我看的别⼈的配置抄的,设置默认的过期时间为1天
重点是cacheManager⽅法:在本⽂中我写了两个⽅法,但是在实际开发中你可以根据RedisConstant⾥⾯常量的数量及需求⾃⾏增加,这样就不需要在⽅法上⾯修改了(万⼀⼀个key在多处调⽤岂不是蛋疼?),⽽且我是为了省事所以所有的都使⽤的
Jackson2JsonRedisSerializer序列化⽅式,但是你可以根据⾃⼰的需要设置每⼀类的序列化⽅式。
注意:
上述配置中.disableCachingNullValues()配置要根据个⼈系统决定!此配置会导致@Cacheable如果返回null会报错,缓存拒绝存储null值:
java.lang.IllegalArgumentException: Cache 'user:' does not allow 'null' values. Avoid storing null via '@Cacheable(unless="#result == null")' or configure Re disCache to allow 'null' via RedisCacheConfiguration.
at org.dis.cache.RedisCache.put(RedisCache.java:139)
不建议进⾏上述配置,⼀⽅⾯报错很难受,另⼀⽅⾯数据如果从数据库中查不到⼤概率数据库中根本就
不存在此条记录,所以让此后的数据继续去查询数据库没什么意义,还不如在缓存中放置⼀个null值的数据,指定过期时间即可。
但是有⼀些特殊的数据需要进⾏上述设置,这个根据个⼈系统决定。
开始使⽤
我⼀般使⽤@Cacheable注解的时候会在service和mapper层之间再加⼀层操作,当然你可以直接使⽤在service层或者dao层的接⼝上,这个随意。
@Override
@Cacheable(value = RedisConstant.USER, key ="#id", condition ="#bool==true", unless ="#result == null")
public UserShow getUser(String id,boolean bool){
return userMapper.userShow(id);
}
上⾯这⼀种存储到缓存⾥⾯key的形式为:user:userId,其中userId为⽅法参数id的值,绝⼤多数情况下建议使⽤keyGenerator,编译过程中可能会解析不到参数名,导致缓存时key拼接错误。
@Override
@Cacheable(value = RedisConstant.CATEGORY, key ="#hodName", unless ="#result == null")
public Object hot(){
return kingdomMapper.selectWithScore();
}
上⾯这⼀种存储到缓存⾥⾯key的形式为:category:hot,其中hot的来源是⽅法名,这个涉及到key的相关取值,本⽂不介绍了。百度⼀⼤堆,但是其他的本⼈没⽤过。。。
下⾯来说⼀下@Cacheable注解的好处:
redisTemplate.opsForValue().get(key)⽅法不⽤写了,直接避免存数据和取数据时数据类型不⼀致情况的出现
缓存为空判断不需要做了,省下⼤堆代码
缓存有效期设置可以在配置⽂件中实现,具体⼈员只管使⽤,防⽌某类数据缓存时间变化时需要改动多处代码
下⾯说⼀下我在配置过程中遇到的坑,希望不要再犯:
最初的时候我在RedisConfig配置⽂件中未配置cacheManager⽅法,同时RedisConstant常量类参数也没有加:,导致的情况是我在⽤Redis可视化⼯具查看数据的时候user和id之间有两个:,虽然不影响使⽤,但是看着蛋疼啊!!
当我配置了cacheManager⽅法之后,测试⼜发现user和id之间没有:符号了,这不更是蛋疼吗?(如果某⼀天user展⽰数据突然要求加⼀个字段,难道我使⽤keys命令查询再删除?要知道⽣产环境明令禁⽌使⽤keys命令啊!)
最终测试的结果是我前⾯的配置个⼈感觉更合适,使⼀类数据放到⼀组,⽅便管理。
如有⾼见敬请指出,在线更新。。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。