当前位置: 代码迷 >> 综合 >> redis学习之:lettuce链接池+RedisTemplate
  详细解决方案

redis学习之:lettuce链接池+RedisTemplate

热度:0   发布时间:2024-03-09 12:03:12.0

背景介绍

由于很多人推荐使用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的同步和异步通信。

注意:jedis连接池每一个jedis实例就是一个jedis链接,所以jedis可以动态的切换redis,db库.new一个jedis实例可以设置一个db库. 但是RedisTemplate不行需要在启动的时候创建一个链接,而且一旦切换就所有的链接都切换了.所以需要启动的时候需要几个db就配置几个template实例.这样不需要动态的切换,需要那个,注入那个就可以了

一、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;}