背景介绍
由于很多人推荐使用RedisTemplate来操作redis,而且springboot至2.2版本开始就已经使用lettuce了,所以换成了lettuce+RedisTemplate
lettuce与jedis链接池对比
Lettuce 和 Jedis 的定位都是Redis的client,所以他们当然可以直接连接redis server。
spring boot框架中已经集成了redis,在1.x.x的版本时默认使用的jedis客户端,现在是2.x.x版本默认使用的lettuce客户端。
Jedis
Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接
Lettuce
Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,应为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。
lettuce主要利用netty实现与redis的同步和异步通信。
一、pom引用
<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>
二、yml配置
spring:application:name: ${
parm.service.name}#redis单机版redis:host: ${
parm.redis.host-name}port: ${
parm.redis.port}# 密码 没有则可以不填password: ${
parm.redis.password}database: ${
parm.redis.db1}timeout: 2000# 如果使用的jedis 则将lettuce改成jedis即可lettuce:pool:max-total: 12# 最大活跃链接数 默认8(使用负值表示没有限制)max-active: 12# 最大空闲连接数 默认8max-idle: 12# 最小空闲连接数 默认0min-idle: 0# 连接池最大阻塞等待时间(使用负值表示没有限制)max-wait: -1
config配置
@Configuration
public class LettuceRedisConfig {
@Autowiredprivate Environment environment;/*** 获取连接池信息** @return* @Scope(value = "prototype")代表原型模式* @Scope(value = "singleton")代表单例模式* Spring定义了多种作用域,可以基于这些作用域创建bean,包括:* 单例( Singleton):在整个应用中,只创建bean的一个实例。* 原型( Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。* 会话( Session):在Web应用中,为每个会话创建一个bean实例。* 请求( Rquest):在Web应用中,为每个请求创建一个bean实例。*/@Bean@ConfigurationProperties(prefix = "spring.redis.lettuce.pool")@Scope(value = "prototype")public GenericObjectPoolConfig redisPool() {
return new GenericObjectPoolConfig();}/*** 获取redis连接池信息** @return*/@Bean@ConfigurationProperties(prefix = "parm.redis")public RedisStandaloneConfiguration redisConfigA() {
return new RedisStandaloneConfiguration();}@Primary@Bean("redisTemplate1")public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = getRedisTemplate(redisConnectionFactory);return redisTemplate;}@Bean("redisTemplate2")public RedisTemplate<String, Object> redisTemplate2(GenericObjectPoolConfig redisPool, RedisStandaloneConfiguration redisConfigA,@Value("${parm.redis.db2}") int database2) {
redisConfigA.setDatabase(database2);LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder = LettucePoolingClientConfiguration.builder();builder.poolConfig(redisPool);LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(redisConfigA, builder.build());connectionFactory.afterPropertiesSet();return getRedisTemplate(connectionFactory);}public RedisTemplate getRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);RedisSerializer<String> stringSerializer = new StringRedisSerializer();redisTemplate.setKeySerializer(stringSerializer);redisTemplate.setHashKeySerializer(stringSerializer);//设置序列化接口ObjectMapper mapper = new ObjectMapper();mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);mapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);mapper.setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE);SimpleFilterProvider filterProvider = new SimpleFilterProvider();filterProvider.setDefaultFilter(SimpleBeanPropertyFilter.serializeAll());mapper.setFilterProvider(filterProvider);GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(mapper);// key序列化redisTemplate.setKeySerializer(stringSerializer);// value序列化redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// Hash key序列化redisTemplate.setHashKeySerializer(stringSerializer);// Hash value序列化redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}}
引用
@Autowired@Qualifier("redisTemplate1")private RedisTemplate<String, Object> redisTemplate;#redisTemplate里有各种redis类型的操作通过 opsFor**()方法来操作具体需要
redisTemplate.opsForHash().put("OTT_" + code + "_" + hashKey, key, value);
获取所有的key
keys方法比较耗费性能,不推荐使用 public static List<String> getkeys(RedisTemplate redisTemplate) {
List<String> result = new ArrayList<>();try {
String patternKey = "*";ScanOptions options = ScanOptions.scanOptions()//这里指定每次扫描key的数量(很多博客瞎说要指定Integer.MAX_VALUE,这样的话跟 keys有什么区别?).count(20).match(patternKey).build();RedisSerializer<String> redisSerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redisConnection -> new ConvertingCursor<>(redisConnection.scan(options), redisSerializer::deserialize));while (cursor.hasNext()) {
result.add(cursor.next().toString());}//切记这里一定要关闭,否则会耗尽连接数。报Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisException: Could not get acursor.close();} catch (IOException e) {
return null;}return result;}