Redis的Java客户端
- 我们最早使用的Redis的Java客户端是Jedis,但是它具有线程安全问题,多线程环境下需要连接池连接。
- Lettuce是基于Netty实现的,支持同步、异步和响应式编程方式,并且是线程安全的。支持Redis哨兵模式、集群模式和管道。因此Srping默认继承Lettuce。
Spring中的Spring Data Redis集成了以上两种客户端。 - Redission是一个一个基于Redis实现的分布式、可伸缩的Java数据结构集合。
Jedis客户端
入门
@BeforeEach由junit5提供,在每个@Test方法执行前,将该注解下的代码执行一遍。
使用步骤:
- 引入依赖
</properties>
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.10.1</version>
</dependency>
</dependencies>
- 创建jedis对象,建立连接(需要的参数:ip、port、密码)
- 操作数据库
- 释放连接
package com.heima.test;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
/**
* @author Zonda
* @version 1.0
* @description TODO
* @2024/7/1 10:00
*/
public class JedisTest {
private Jedis jedis;
@BeforeEach
void setup(){
jedis = new Jedis("192.168.101.65",6379);
jedis.auth("123321");
jedis.select(0);
}
@Test
void test(){
jedis.set("name", "zonda");
System.out.println(jedis.get("name"));
}
@Test
void testmap(){
HashMap<String, String> map = new HashMap<>();
map.put("zonda", "man");
map.put("lucy", "woman");
jedis.hset("user:1",map);
System.out.println(map);
}
@AfterEach
void close(){
if(jedis != null){
jedis.close();
}
}
}
Jedis线程池
连接池的几个主要参数:
- 最大连接
- 最大空闲连接
- 最小空闲连接
- 最长等待时间:连接池的最长等待时间通常是指在连接池中没有可用连接时,客户端尝试获取连接的最大等待时间。
Jedis本身是不安全的,并且频繁创建和销毁连接会有性能损耗,因此可以使用Jedis连接池代替Jedis。
- 首先用工厂模式创建连接池对象
package com.heima.jedis.util;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* @author Zonda
* @version 1.0
* @description TODO
* @2024/7/1 10:25
*/
public class JedisConnectionFactory {
private static final JedisPool jedisPool;
static{
//连接池配置类
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//配置最大连接数
jedisPoolConfig.setMaxTotal(8);
//设置最大空闲连接数
jedisPoolConfig.setMaxIdle(8);
//设置最小空闲连接数
jedisPoolConfig.setMinIdle(0);
//设置最长等待时间,这里是获取线程池的最长等待时间
jedisPoolConfig.setMaxWaitMillis(20);
//建立连接池
jedisPool = new JedisPool(jedisPoolConfig,
"192.168.101.65",
6379,
1000,
"123321");//1000是建立Redis连接的最长等待时间
}
public static Jedis getJedisPool(){
//调用getResource()获取Jedis对象
return jedisPool.getResource();
}
}
- 将Jedis中的
jedis = new Jedis("192.168.101.65",6379);
改为
jedis = JedisConnectionFactory.getJedisPool();
SpringDataRedis
SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis,官网地址:https://spring.io/projects/spring-data-redis
- 提供了对不同Redis客户端的整合(Lettuce和Jedis)
- 提供了RedisTemplate统一API来操作Redis
- 支持Redis的发布订阅模型
- 支持Redis哨兵和Redis集群
- 支持基于Lettuce的响应式编程
- 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
- 支持基于Redis的JDKCollection实现(如链表、队列,因为在Redis中是分布式、跨系统的)
在Jedis中,每一种方法对应着一种操作指令(如set对应jedis.set()),所以学习成本较低,但是较为臃肿。
但是SpringDataRedis中提供的RedisTemplate工具类,封装了各种对于Redis的操作,将不同数据类型的操作API封装到不同类型中。
测试SpringDataRedis:
- 创建一个SpringBoot的项目,在依赖选择中选择SpringDataRedis,这样创建好的项目中就已经引入了该依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 引入common依赖,这个依赖用于线程池操作
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
- 在application.yaml中配置Redis的信息(yaml中配置)
spring:
redis:
host: 192.168.101.65
port: 6379
password: 123321
lettuce:
pool:
max-active: 8
min-idle: 0
max-idle: 8
max-wait: 1000
- 注入RedisTemplate
- 编写测试
package org.example.springdataredisdemo;
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;
@SpringBootTest
class SpringdataredisdemoApplicationTests {
@Autowired
RedisTemplate redisTemplate;
@Test
void contextLoads() {
redisTemplate.opsForValue().set("name", "Luka Magic");
Object name = redisTemplate.opsForValue().get("name");
System.out.println(name);
}
}
RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,因为我们是自动注入的RedisTemplate,默认是采用JDK序列化,得到的结果是这样的:
这样的方式有两个缺点:
- 可读性cha
- 内存占用较大
那么我们该如何用我们想要的序列化方式来序列化键值对呢?解决方法:不用默认的JDK序列化
其实RedisSerializer有很多实现类:
- 一般对于肯定为字符串的。一般是key用StringRedisSerializer
- 可能为字符串可能为对象的,一般是value用GenericJackson2JsonRedisSerializer
可以通过@Configuration来声明一个我们想要的RedisTemplate类,在这个类内部定义序列化方式。由RedisTemplate源码,可以看出该类中有四个可以设置的序列化的对象,分别是key、value、hashkey、hashvalue:
@Nullable
private RedisSerializer keySerializer = null;
@Nullable
private RedisSerializer valueSerializer = null;
@Nullable
private RedisSerializer hashKeySerializer = null;
@Nullable
private RedisSerializer hashValueSerializer = null;
RedisConnectionFactory 用于创建和管理 RedisConnection 实例。在Spring Data Redis中,这是与Redis服务器通信的主要入口点,所以。
- 首先要配置依赖项(注意:要引入jackson-databind依赖):
- 再重写RedisConfig类
package com.heima.redis.config;
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.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
/**
* @author Zonda
* @version 1.0
* @description TODO
* @2024/7/1 12:31
*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory){
//创建RedisTemplate对象
RedisTemplate<String, Object> template = new RedisTemplate<>();
//配置连接工厂
template.setConnectionFactory(connectionFactory);
//创建JSON序列化工具
GenericJackson2JsonRedisSerializer json = new GenericJackson2JsonRedisSerializer();
//设置Key的序列化
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
//设置Value的序列化
template.setValueSerializer(json);
template.setHashKeySerializer(json);
//返回
return template;
}
}
- 再改一下自动注入的redisTemplate的类型
@Autowired
private RedisTemplate redisTemplate;
改为:
@Autowired
private RedisTemplate<String,Object> redisTemplate;
-
当然也可以传入对象,Redis可以自动将对象序列化存入,在取出的时候再反序列化
- 先创建一个User类:
package com.heima.redis.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author Zonda * @version 1.0 * @description TODO * @2024/7/1 14:33 */ @Data @NoArgsConstructor @AllArgsConstructor public class User { private String name; private Integer age; }
- 再测试存入对象
@Test void testSaveUser(){ redisTemplate.opsForValue().set("user:100", new User("zonda",25)); Object o = redisTemplate.opsForValue().get("user:100"); System.out.println(o); }
-
在Resp客户端中查找users对象,是以JSON的形式存储的,同时还存储了类的字节码"@class": “com.heima.redis.pojo.User”,这样会占用大量的内存空间,但是要想实现自动序列化和反序列化又不得不存类的字节码文件。
但是如果存储千万级别的对象,肯定是不能存储类字节码文件的,所以我们一般都不使用JSON序列化器,而是统一使用String序列化器。当需要存储Java对象的时候,手动完成对象的序列化和反序列化。如下图所示,这样就可以解决内存占用问题了。 -
那我们是否也要像RedisTemplate<String, Object> template = new RedisTemplate<>();一样去构造一个新的RedisTemplate呢?但是不需要,因Spring提供了一个StringRedisTemplate类,它的K-V的序列化方式默认是String,省去了自定义的过程。
-
我们可以用
- mapper.writeValueAsString(user)手动序列化对象。
- mapper.readValue(val,User.class)手动反序列化对象。
package com.heima; import com.fasterxml.jackson.databind.ObjectMapper; import com.heima.redis.pojo.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.StringRedisTemplate; /** * @author Zonda * @version 1.0 * @description TODO * @2024/7/1 14:55 */ @SpringBootTest public class stringRedisTemplate { @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private static final ObjectMapper mapper = new ObjectMapper(); @Test void testTemplate() throws Exception{ User jordan = new User("Jordan", 50); String s = mapper.writeValueAsString(jordan); stringRedisTemplate.opsForValue().set("user:101",s); String s1 = stringRedisTemplate.opsForValue().get("user:101"); Object o = mapper.readValue(s1, User.class); System.out.println((User)o); } }
打开RESP可以发现没有类的字节码了:
- 总结
- RedisTemplate也可以存和取hash值,用stringRedisTemplate.opsForHash()获取操作类。
@Test
void testSet() throws Exception{
stringRedisTemplate.opsForHash().put("user:102","name","Durant");
stringRedisTemplate.opsForHash().put("user:102","age","22");
Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("user:102");
System.out.println(entries);
}
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » 黑马点评DAY3|Redis的Java客户端
发表评论 取消回复