1. Redis的Java客户端简介
在Redis官网中提供了各种语言的客户端,地址:https://redis.io/docs/connect/clients/
其中Java客户端也包含很多:
标记为*的就是推荐使用的java客户端,包括:
-
Jedis和Lettuce:这两个主要是提供了Redis命令对应的API,方便我们操作Redis,而SpringDataRedis又对这两种做了抽象和封装,因此我们后期会直接以SpringDataRedis来学习。
-
Redisson:是在Redis基础上实现了分布式的可伸缩的java数据结构,例如Map、Queue等,而且支持跨进程的同步机制:Lock、Semaphore等待,比较适合用来实现特殊的功能需求。
2. Jedis客户端与pringDataRedis客户端的区别
Jedis是一个Java的Redis客户端,而Spring Data Redis是Spring提供的用于与Redis进行集成的库。它们之间有以下几个区别:
- 定位与使用方式:
- Jedis: Jedis客户端提供了直接的、原生的Redis操作API,是对Redis命令的直接封装。开发者可以直接使用Jedis提供的方法来操作Redis,需要自己处理连接管理、连接池和序列化等问题。
- Spring Data Redis: Spring Data Redis是在Jedis的基础上进行的进一步封装,提供了更高级的特性和更方便的使用方式。它是Spring框架的一部分,通过提供一组简化的API,减少了开发者对底层Redis连接和操作的关注。
-
功能与特性:
- Jedis: Jedis提供了对Redis命令的完整覆盖,支持执行各种Redis命令和事务操作。但是,Jedis对于一些高级特性比如连接池、集群、管道等的支持相对较弱,需要开发者自己实现。
- Spring Data Redis: Spring Data Redis在Jedis的基础上提供了更多的高级特性,如对象序列化、缓存、分布式锁、响应式编程等。它抽象了连接管理和序列化等细节,提供了更简单、更易于使用的API。
-
扩展性:
- Jedis: Jedis是一个独立的Redis客户端,可以根据特定业务需求进行定制和扩展。开发者可以自行封装Jedis的使用方式,或者基于其底层实现自定义功能。
- Spring Data Redis: Spring Data Redis基于Spring框架,充分利用了Spring的扩展机制。它提供了很多扩展点,可以通过自定义实现接口来定制和扩展更多的功能。
总的来说,Jedis是一个原生且灵活的Redis客户端,适用于需要直接对Redis进行精细控制的场景。而Spring Data Redis是在Jedis基础上进行封装的高级Redis集成库,提供了更简化的API和更高级的特性,适用于开发者希望使用Spring框架进行集成和更高层次抽象的场景。
3. Jedis客户端
Jedis的官网地址: GitHub - redis/jedis: Redis Java client
3.1 引入Maven依赖
<!-- 单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
</dependency>
<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
</dependency>
3.2 建立连接池
Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式。
package com.zsh.redistest.demos.common.config;
import redis.clients.jedis.*;
/**
* Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式。
* @Author ZhaoShuHao
* @create 2023/11/19
*/
public class JedisConnectionFactory {
private static JedisPool jedisPool;
static {
// 配置连接池
JedisPoolConfig poolConfig = new JedisPoolConfig();
//设置连接池中允许的最大活跃(正在使用)连接数。在这里,它被设置为8,表示连接池中最多允许有8个活跃连接。
poolConfig.setMaxTotal(8);
//设置连接池中允许的最大空闲连接数。在这里,它被设置为8,表示连接池中最多允许有8个空闲连接。
poolConfig.setMaxIdle(8);
//设置连接池中维持的最小空闲连接数。在这里,它被设置为0,表示连接池中最少要维持0个空闲连接。
poolConfig.setMinIdle(0);
//设置当连接池中没有可用连接时,应用程序请求连接的最大等待时间,超过该时间将抛出异常。在这里,它被设置为1000毫秒(1秒),表示当没有可用连接时,应用程序最多等待1秒。
poolConfig.setMaxWaitMillis(1000);
// 创建连接池对象,参数:连接池配置、服务端ip、服务端端口、超时时间、密码
jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379, 1000);
}
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
3.3 编写测试类
package com.zsh.redistest.demos.controller;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
import java.util.Map;
import static com.zsh.redistest.demos.common.config.JedisConnectionFactory.getJedis;
/**
* @Author ZhaoShuHao
* @create 2023/11/19
*/
public class JedisTest {
@Test
void testString() {
Jedis jedis = getJedis();
// 存入数据
String result = jedis.set("name", "南风");
System.out.println("result = " + result);
// 获取数据
String name = jedis.get("name");
System.out.println("name = " + name);
}
@Test
void testHash() {
Jedis jedis = getJedis();
// 插入hash数据
jedis.hset("user:1", "name", "南风");
jedis.hset("user:1", "age", "23");
// 获取
Map<String, String> map = jedis.hgetAll("user:1");
System.out.println(map);
}
}
4.SpringDataRedis客户端
SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis,官网地址:Spring Data Redis
-
提供了对不同Redis客户端的整合(Lettuce和Jedis)
-
提供了RedisTemplate统一API来操作Redis
-
支持Redis的发布订阅模型
-
支持Redis哨兵和Redis集群
-
支持基于Lettuce的响应式编程
-
支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
-
支持基于Redis的JDKCollection实现
SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:
// redisTemplate #操作不同的数据类型,api和我们的指令是一样的
// opsForValue #操作字符串 类似String
// opsForList #操作List 类似List
// opsForSet #操作set
// opsForHash #操作hash
// opsForZSet #操作zset
// opsForGeo #操作geo
// opsForHyperLogLog #操作HyperLogLog
// 除了基本的操作,我们常用的方法都可以直接通过redisTemplate操作,比如事务,和基本的 CRUD
// 获取redis的连接对象
// RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
// connection.flushDb();
// connection.flushAll();
4.1 引入Maven依赖
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--common-pool-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--Jackson依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</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>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- 单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
</dependency>
4.2 配置redis
server:
port: 8080
redis:
host: localhost
port: 6379
lettuce:
pool:
max-active: 8 #连接池中允许的最大活动(正在使用)的连接数
max-idle: 8 #连接池中允许的最大空闲连接数。
min-idle: 0 #连接池中维持的最小空闲连接数。
max-wait: 100ms #当连接池中没有可用连接时,最大等待时间,超过该时间将抛出异常
4.3 编写测试类
这里模拟了一下token过期的业务场景
package com.zsh.redistest.demos.common.constant;
/**
* 常量
* @Author ZhaoShuHao
* @create 2023/11/19
*/
public class WechatConstant {
//键
public static String REDISTOKENKEY = "wechat:token";
//过期时间(单位秒),一般企业微信的过期时间是2小时(7200秒)
public static int REDISTOKENTIMEOUT = 7200;
}
package com.zsh.redistest.demos.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
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;
import org.springframework.util.StringUtils;
import java.util.concurrent.TimeUnit;
import static com.zsh.redistest.demos.common.constant.WechatConstant.*;
/**
* @Author ZhaoShuHao
* @create 2023/11/19
*/
@SpringBootTest
class RedisStringTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
// JSON序列化工具
private static final ObjectMapper mapper = new ObjectMapper();
//保存token,并设置过期时间
public String saveToken(){
//假设获取到了企业微信的token
String token = "isujagfuisdgfijsdhfojhjsdaoffsafsa";
// 写入数据
stringRedisTemplate.opsForValue().set(REDISTOKENKEY, token);
//设置过期时间
stringRedisTemplate.expire(REDISTOKENKEY, REDISTOKENTIMEOUT, TimeUnit.SECONDS);
// 获取数据
String result = stringRedisTemplate.opsForValue().get(REDISTOKENKEY);
if(StringUtils.isEmpty(result)){
System.out.println("token保存失败");
}else {
System.out.println("token保存成功");
}
return result;
}
//获取token是否过期
public String getToken(){
String token = null;
// 获取数据
Long expire = stringRedisTemplate.opsForValue().getOperations().getExpire(REDISTOKENKEY);
System.out.println(expire);
//getExpire()方法的返回值单位为秒,-2表示键不存在或已过期,-1表示键存在但未设置过期时间。
if(expire== -2){
System.out.println("token已过期");
}else {
System.out.println("token未过期");
token = stringRedisTemplate.opsForValue().get(REDISTOKENKEY);
}
return token;
}
//获取token,先判断是否过期,若过期就保存,并拿到token.若未过期就直接获取token
@Test
public void changeToken(){
String token = getToken();
if(StringUtils.isEmpty(token)){
saveToken();
}else {
System.out.println("获取到token:"+token);
}
}
}
4.4 StringRedisTemplate与RedisTemplate的区别
StringRedisTemplate
和RedisTemplate
是Spring Data Redis库提供的两种常用的Redis操作模板类,它们在功能和使用方式上有一些区别。
-
数据存储方式:
StringRedisTemplate
用于与Redis服务器交互存储字符串类型的数据,例如简单的键值对。RedisTemplate
用于与Redis服务器交互存储任意类型的数据,包括字符串、对象等。
-
序列化和反序列化:
StringRedisTemplate
默认使用的是Redis的字符串序列化器,将对象转换为字符串存储在Redis中。RedisTemplate
提供了对多种序列化器的支持,默认使用JDK的序列化器,也可以配置为其他的序列化方式,如JSON、Jackson等。
-
方法调用:
StringRedisTemplate
提供了更简洁方便的API,专门针对字符串类型数据的操作。例如,opsForValue()
方法返回的是ValueOperations<String, String>
对象,提供了字符串类型数据的操作方法。RedisTemplate
提供了更通用、灵活的API,可以处理更多种类的数据。例如,通过opsForValue()
方法,可以返回ValueOperations<String, Object>
对象,进行字符串和对象类型数据的操作。
选择使用 StringRedisTemplate
还是RedisTemplate
取决于您存储的数据类型以及应用程序的需求。如果您只需要存储简单的键值对且值为字符串类型,可以选择使用StringRedisTemplate
。如果您需要存储多种类型的数据,或者对数据的序列化方式有特殊需求,可以选择使用RedisTemplate
。
在性能方面,StringRedisTemplate和RedisTemplate的区别主要体现在两个方面:序列化和操作命令。
-
序列化:
- StringRedisTemplate:StringRedisTemplate默认使用的是String的序列化策略,将数据以字符串的形式存储在Redis中。这种序列化方式对于存储简单的字符串数据非常高效,不需要进行额外的序列化和反序列化处理。
- RedisTemplate:RedisTemplate默认使用的是JDK的序列化策略,将数据以二进制的形式存储在Redis中。虽然JDK序列化支持处理复杂的数据类型,但它在性能上相对较低,并且存储的数据在Redis中是以二进制形式展示的。
-
操作命令:
- StringRedisTemplate:StringRedisTemplate提供了更多针对字符串数据的特定命令操作,例如set、get、incr等,这些命令直接对应于Redis的命令,使用更为简单和直观。
- RedisTemplate:RedisTemplate提供了更加通用的操作方法,适用于操作更复杂的数据结构(例如Hash、List、Set等)。但对于简单字符串操作,需要开发者进行一些额外的封装和转换。
综上,在性能方面,StringRedisTemplate由于使用了较为简洁的字符串序列化策略,可以在存储简单文本数据时有较好的性能表现。而RedisTemplate由于支持更多复杂数据类型和自定义序列化策略,适用于处理数据结构较为复杂的场景。当需要在性能和灵活性之间做出选择时,可以根据具体场景来选择使用StringRedisTemplate或RedisTemplate。
5. 关于Redis的图形化桌面客户端
GitHub上的大神编写了Redis的图形化桌面客户端,地址:GitHub - RedisInsight/RedisDesktopManager
不过该仓库提供的是RedisDesktopManager的源码,并未提供windows安装包。
在下面这个仓库可以找到安装包:Releases · lework/RedisDesktopManager-Windows · GitHub
下载安装后,双击运行RDM,点击连接到redis服务器,输入相关信息,即可连接redis,进行图形化操作。