一、关于Lettuce
在SpringBoot2.0.x版本中集成Redis,Lettuce现已取代Jedis作为Redis驱动。那Lettuce又是个什么呢?与Jedis又有何区别呢?
Lettuce 是一个可伸缩的线程安全的 Redis 客户端,支持同步、异步和响应式模式。多个线程可以共享一个连接实例,而不必担心多线程并发问题。它基于优秀 Netty NIO 框架构建,支持 Redis 的高级功能,如 Sentinel,集群,流水线,自动重新连接和 Redis 数据模型
Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接 Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,应为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。
二、SpringBoot集成Redis实操
POM依赖 本地下载JAR包好慢啊,这网太破了。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<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>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
</dependencies>
配置文件中配置与redis有关的属性
spring.redis.host=192.168.159.128
spring.redis.port=6379
spring.redis.password=redis
#连接超时时间(毫秒)
spring.redis.timeout=10000ms
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=16
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池最大阻塞等待时间,单位毫秒(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=1000ms
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.shutdown-timeout=100ms
2、 redis配置
接下来我们需要配置redis的key跟value的序列化方式,默认使用的JdkSerializationRedisSerializer
这样的会导致我们通过redis desktop manager
显示的我们key跟value的时候显示不是正常字符。 所以我们需要手动配置一下序列化方式 新建一个config
包,在其下新建一个RedisConfiguration.java
具体代码如下
package com.wang.redis.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfiguration {
/**
* 配置自定义redisTemplate
* @return
*/
@Bean
RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
}
其中@Configuration
代表这个类是一个配置类,然后@AutoConfigureAfter(RedisAutoConfiguration.class)
是让我们这个配置类在内置的配置类之后在配置,这样就保证我们的配置类生效,并且不会被覆盖配置。其中需要注意的就是方法名一定要叫redisTemplate
因为@Bean
注解是根据方法名配置这个bean的name的。
3、测试
我们需要测试在redis缓存对象的用例,所以我们需要新建一个实体类。
代码如下:
package com.wang.redis;
import com.wang.redis.entry.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest
public class RedisTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void redisTest() {
// redis存储数据
String key = "redis_name_wangchao_01";
redisTemplate.opsForValue().set(key, "wangchao");
// 获取数据
String value = (String) redisTemplate.opsForValue().get(key);
System.out.println("获取redis中key为" + key + "的值为:" + value);
//User user =User.builder().id(1L).username("wangchao").age(19).sex(1).build();
User user = new User();
user.setUsername("wangchao");
user.setSex(18);
user.setId(1L);
String userKey = "edis_name_wangchao_"+user.getId();
redisTemplate.opsForValue().set(userKey, user);
User newUser = (User) redisTemplate.opsForValue().get(userKey);
System.out.println("获取redis中key为" + userKey + "的User值为:" + newUser);
}
}
测试通过。OK
备注:对象序列化过程中,User对象构建方式不一致,导致结果出现差异。
# 使用Lombok注解 @Builder,需显示增加对象的无参构造器获取使用Lombok的无参构造注解。
User user =User.builder().id(1L).username("wangchao").age(19).sex(1).build();
User user = new User();
在User.builder().id(1L).username("wangchao").age(19).sex(1).build();方式,是使用Lombok注解生成构建者模式。若对象没有添加无参构造器,则对象会在反序列化过程中报错。