(二)连接Redis,Lettuce与Jedis客户端
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(二)连接Redis,Lettuce与Jedis客户端相关的知识,希望对你有一定的参考价值。
参考技术A Redis优势从 Spring Boot 2.x 开始 Lettuce 已取代 Jedis 成为首选 Redis 的客户端。当然 Spring Boot 2.x 仍然支持 Jedis,并且你可以任意切换客户端。
使用Lecttuce需要再引用一个包
配置
org.springframework.boot.autoconfigure.data.redis.RedisProperties中集成了Jedis与Lettuce。
概念:
Jedis:是Redis的Java实现客户端,提供了比较全面的Redis命令的支持,
Redisson:实现了分布式和可扩展的Java数据结构。
Lettuce:高级Redis客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。
优点:
Jedis:比较全面的提供了Redis的操作特性
Redisson:促使使用者对Redis的关注分离,提供很多分布式相关操作服务,例如,分布式锁,分布式集合,可通过Redis支持延迟队列
Lettuce:主要在一些分布式缓存框架上使用比较多
可伸缩:
Jedis:使用阻塞的I/O,且其方法调用都是同步的,程序流需要等到sockets处理完I/O才能执行,不支持异步。Jedis客户端实例不是线程安全的,所以需要通过连接池来使用Jedis。
Redisson:基于Netty框架的事件驱动的通信层,其方法调用是异步的。Redisson的API是线程安全的,所以可以操作单个Redisson连接来完成各种操作
Lettuce:基于Netty框架的事件驱动的通信层,其方法调用是异步的。Lettuce的API是线程安全的,所以可以操作单个Lettuce连接来完成各种操作
Redis 学习笔记Jedis & Lettuce
前言:Jedis是之前被推荐的最为广泛的操作Redis的客户端连接开发工具,现在被lettuce代替了,我们简单了解一下这个的使用吧。
1.导入Jedis依赖
1.jedis坐标如下
<dependencies>
<!-- 导入jedis-->
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.5.2</version>
</dependency>
<!-- 导入fastjson-->
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
</dependencies>
2.Java端测试连接
public class TestPing {
public static void main(String[] args) {
//new 一个Jedis对象即可
Jedis jedis = new Jedis("127.0.0.1",6379);
// 返回PING代表连接成功
System.out.println(jedis.ping());
//关机连接
jedis.close();
}
}
3.使用Jedis开启事务
public class TestTX {
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1",6379);
JSONObject jsonObject = new JSONObject();
jsonObject.put("name","zhangsan");
jsonObject.put("age","18");
String s = jsonObject.toString();
//开启事务
Transaction multi = jedis.multi();
try {
multi.set("user1",s);
multi.set("user2",s);
//执行事务
multi.exec();
} catch (Exception e) {
//放弃事务
multi.discard();
e.printStackTrace();
}finally {
System.out.println(jedis.get("user1"));
System.out.println(jedis.get("user2"));
//关闭连接
jedis.close();
}
}
}
2.SpringBoot整合Redis
- 导入基本坐标:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 说明:在SpringBoot2.x之后,原来使用的jedis被替换为了lettuce
- jedis:采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全,使用jedis pool连接池。BIO模式
- lettuce:采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况。可以减少线程数量,更像NIO模式
redis自动配置类分析
1.自动配置类,专门提取了一个操作String字符串的实例(StringRedisTemplate)
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")//在没有redisTemplate这个bean时才生效,这样我们可以自定义一个RedisTemple来替换。
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
//默认的RedisTemplate没有过多的设置,redis对象都是需要序列化。(尤其是使用了netty这种异步通信,默认使用jdk序列化)
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
2.配置
spring:
redis:
host: 192.168.242.132 //虚拟机的ip
port: 6379
3.测试
@Test
void contextLoads() {
redisTemplate.opsForValue().set("name","zhangsan");
System.out.println(redisTemplate.opsForValue().get("name"));
}
############控制台###############
zhangsan
3.关于Redis序列化问题
1.准备一个对象
@Component
@NoArgsConstructor
@AllArgsConstructor
@Data
public class User{
private String name;
private int age;
}
2.测试添加到redis中
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
//真实的开发一般都是使用json来传递对象
User user = new User("张三", 3);
redisTemplate.opsForValue().set("user", user);
System.out.println(redisTemplate.opsForValue().get("user"));
}
异常抛出:(形成的原因就是实体类未实现序列化接口 Serializable)
org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is org.springframework.core.NestedIOException: Failed to deserialize object type; nested exception is java.lang.ClassNotFoundException: com.zzgele.qmkx.info.enums.InfomationTypeEnum
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:84) ~[spring-data-redis-2.0.7.RELEASE.jar!/:2.0.7.RELEASE]
at org.springframework.data.redis.serializer.SerializationUtils.deserializeValues(SerializationUtils.java:54) ~[spring-data-redis-2.0.7.RELEASE.jar!/:2.0.7.RELEASE]
at org.springframework.data.redis.serializer.SerializationUtils.deserialize(SerializationUtils.java:68) ~[spring-data-redis-2.0.7.RELEASE.jar!/:2.0.7.RELEASE]
at org.springframework.data.redis.core.AbstractOperations.deserializeValues(AbstractOperations.java:268) ~[spring-data-redis-2.0.7.RELEASE.jar!/:2.0.7.RELEASE]
at org.springframework.data.redis.core.DefaultListOperations.lambda$range$6(DefaultListOperations.java:171) ~[spring-data-redis-2.0.7.RELEASE.jar!/:2.0.7.RELEASE]
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:224) ~[spring-data-redis-2.0.7.RELEASE.jar!/:2.0.7.RELEASE]
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:184) ~[spring-data-redis-2.0.7.RELEASE.jar!/:2.0.7.RELEASE]
at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:95) ~[spring-data-redis-2.0.7.RELEASE.jar!/:2.0.7.RELEASE]
at org.springframework.data.redis.core.DefaultListOperations.range(DefaultListOperations.java:171) ~[spring-data-redis-2.0.7.RELEASE.jar!/:2.0.7.RELEASE]
at com.zzgele.qmkx.info.service.impl.InfomationServiceImpl.refreshInfo(InfomationServiceImpl.java:1116) ~[classes!/:0.0.1-SNAPSHOT]
3.添加到redis中数据被转义,形成了一堆看不懂的东西
4.追加到RedisTemplate中的序列化方式
5.默认实现(JDK序列化)
if (this.defaultSerializer == null) {
this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
}
if (this.enableDefaultSerializer) {
if (this.keySerializer == null) {
this.keySerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.valueSerializer == null) {
this.valueSerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.hashKeySerializer == null) {
this.hashKeySerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.hashValueSerializer == null) {
this.hashValueSerializer = this.defaultSerializer;
defaultUsed = true;
}
6.如何修改默认序列化方式?
- 在其中提供了setKeySerializer方法,参数只需要传入序列化方式即可。
补充:RedisSerializer是个接口,里面提供多种方式,这里我们使用常用的Jackson序列化方式
7.修改Redis序列化的模板如下:
@Configuration
public class RedisConfig {
//编写自定义的RedisTemplate
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
//设置Redis连接工厂
template.setConnectionFactory(redisConnectionFactory);
//Json序列化配置
//传入Object对象
Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jsonRedisSerializer.setObjectMapper(objectMapper);
//String 序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key 采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
//hash的key 采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
//value 采用json的序列化方式
template.setValueSerializer(jsonRedisSerializer);
//hash的value 采用json的序列化方式
template.setHashValueSerializer(jsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
8.再次查看redis中存入的数据
127.0.0.1:6379> keys *
1) "user"
127.0.0.1:6379>
序列化完成
以上是关于(二)连接Redis,Lettuce与Jedis客户端的主要内容,如果未能解决你的问题,请参考以下文章
redis网络波动,Jedis/Lettuce是阻塞还是失败?