SpringBoot使用Redis
欢迎光临我的博客[http://poetize.cn],前端使用Vue2,聊天室使用Vue3,后台使用Spring Boot
1.添加Redis依赖
<!-- spring boot redis 缓存引入 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.添加配置文件
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0
3.使用
@Autowired
private StringRedisTemplate<Object,Object> stringRedisTemplate;
//StringRedisTemplate的构造器中,设置的序列化器是字符串,所以它只能存取字符串
stringRedisTemplate.opsForValue().set("aaa", "111");
4.存储对象
将POJO类实现Serializable接口即可
//redisTemplate 序列化使用的jdkSerializeable, 存储二进制字节码(可以自定义序列化)
//使用Jackson2JsonRedisSerialize 替换默认序列化
redisTemplate.opsForValue().set("user", user);
User user1 = (User) redisTemplate.opsForValue().get("user");
5.配置连接池(application.yml配置文件)
SpringBoot2.0默认采用Lettuce客户端来连接Redis服务端的。
默认是不使用连接池的,配置文件中添加lettuce.pool相关配置,则会使用到lettuce连接池,并将相关配置设置为连接池相关参数。
Lettuce 和 Jedis 的都是连接Redis Server的客户端程序。Jedis在实现上是直连redis server,多线程环境下
非线程安全
,除非使用连接池,为每个Jedis实例增加物理连接。Lettuce基于Netty的连接实例(StatefulRedisConnection),可以在多个线程间并发访问,且线程安全
,满足多线程环境下的并发访问
SpringBoot会自动配置redis,注入相关bean
spring:
redis:
host: localhost # reids的连接ip
database: 0 # Redis默认情况下有16个分片,这里配置具体使用的分片,默认是0
timeout: 10000ms # 连接超时时间(毫秒)
lettuce: # springboot2.0后默认使用lettuce连接redis,底层使用的是netty框架做支撑
pool:
min-idle: 0 # 连接池中的最小空闲连接 默认 0
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
max-active: 8 # 连接池最大连接数(使用负值表示没有限制) 默认 8
max-idle: 8 # 连接池中的最大空闲连接 默认 8
6.编写缓存配置类CacheConfig用于调优缓存默认配置
默认提供的Redis集成使用起来会有几个问题:
- 生成Key过于简单,容易出现冲突。
- 无法设置过期时间,乃至无法个性化每个业务单独的过期时间。
- 默认配置序列化采用JDK序列化,某些业务场景无法满足。
考虑以上几个问题,我们通常在集成使用Redis时,会自定义一些配置,这里我们来看看如何做自定义配置。
@Configuration
@EnableCaching //开启缓存支持
public class RedisConfig extends CachingConfigurerSupport {
/**
* 重写key生成策略,缓存的key是包名+方法名+参数列表,这样就很难会冲突了
*/
@Bean
@Override
public KeyGenerator keyGenerator() {
return (target, method, objects) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append("::" + method.getName() + ":");
for (Object obj : objects) {
sb.append(obj.toString());
}
return sb.toString();
};
}
/**
* 缓存配置管理器
*/
@Bean
public CacheManager cacheManager(LettuceConnectionFactory lettuceConnectionFactory) {
//以锁写入的方式创建RedisCacheWriter对象
RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(lettuceConnectionFactory);
//创建默认缓存配置对象
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
//设置默认过期时间是30秒
config.entryTtl(Duration.ofSeconds(30));
//自定义cacheConfig
Map<String, RedisCacheConfiguration> initialCacheConfigurations = new HashMap<>();
for (Map.Entry<String, Integer> entry : CacheExpiresMap.get().entrySet()) {
String key = entry.getKey();
Integer seconds = entry.getValue();
LOGGER.info("key{},value{}", key, seconds);
RedisCacheConfiguration initialCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
initialCacheConfigurations.put(key, initialCacheConfig.entryTtl(Duration.ofSeconds(seconds)));
}
//初始化RedisCacheManager
RedisCacheManager cacheManager = new RedisCacheManager(writer, config,initialCacheConfigurations);
return cacheManager;
}
/**
* RedisTemplate配置
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
// 设置序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =
new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, Visibility.ANY);
om.enableDefaultTyping(DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置redisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
RedisSerializer stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer); // key序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // value序列化
redisTemplate.setHashKeySerializer(stringSerializer); // Hash key序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); // Hash value序列化
//redisTemplate.setEnableTransactionSupport(true); //是否启用事务
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Override
@Bean
public CacheErrorHandler errorHandler() {
// 异常处理,当Redis发生异常时,打印日志,但是程序正常走
LOGGER.info("初始化 -> [{}]", "Redis CacheErrorHandler");
CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
@Override
public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
LOGGER.error("Redis occur handleCacheGetError:key -> [{}]", key, e);
}
@Override
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
LOGGER.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e);
}
@Override
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
LOGGER.error("Redis occur handleCacheEvictError:key -> [{}]", key, e);
}
@Override
public void handleCacheClearError(RuntimeException e, Cache cache) {
LOGGER.error("Redis occur handleCacheClearError:", e);
}
};
return cacheErrorHandler;
}
}