Redis 的 JAVA 客户端

Jedis 优缺点

优点:Redis的命令就是Jedis的方法名,学习成本相对比较低。

缺点:Jedis的实力是线程不安全的,多线程环境下需要基于连接池使用

Lettuce 的优缺点

基于Netty实现的,支持同步异步和响应式编程方式,并且是线程安全的。支持Redis的哨兵模式、集群模式、管道模式。

Redissson 的优缺点

基于Redis实现的分布式、可伸缩的Java数据集合。在分布式条件下实现了Map、Queue、Lock等强大功能。

Spring Data Redis

整合了 Jedis 和 Lettuce。

Jedis 在 Maven 上的使用

Jedis 的基本使用步骤

  1. 引入依赖
  2. 创建jedis对象,并建立链接
  3. 使用Jedis,方法名于Redis命令一致
  4. 释放资源

例:

单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package top.zargo.test;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;

import java.util.Map;

public class JedisTest {
private Jedis jedis;

@BeforeEach
void setUp() {
// 连接Redis服务器
jedis = new Jedis("123.207.22.15", 6379);
jedis.auth("Ljj20010315_");
jedis.select(1);
}

@Test
void testString() {
jedis.set("name", "李俊杰");
jedis.set("age", "23");
String name = jedis.get("name");
String age = jedis.get("age");
System.out.println(name);
System.out.println(age);
}

@Test
void testHash() {
jedis.hset("user:1", "name", "李俊杰");
jedis.hset("user:1", "age", "24");
String name = jedis.hget("user:1", "name");
String age = jedis.hget("user:1", "age");
System.out.println(name);
System.out.println(age);
Map<String, String> stringStringMap = jedis.hgetAll("GoldPrice:itemName:Gold");
System.out.println(stringStringMap);
}

@AfterEach
void tearDown() {
if(jedis != null) {
jedis.close();
}
}
}

Jedis本身是线程不安全的,频繁的创建和销毁链接会有性能的损耗,因此建议使用连接池来代替Jedis的直连。

Jedis 的连接池

首先建立一个工具类用来创建链接池,用static final创建静态的JedisPool对象,并使用static{}静态代码块完成对象初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class jedisConnectionFactory {
private static final JedisPool jedisPoll;
//final 定义的引用类型变量 在类初始化完成之前 必须被初始化
static {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//最大链接
jedisPoolConfig.setMaxTotal(8);
//最大空闲链接
jedisPoolConfig.setMaxIdle(8);
//最小空闲链接
jedisPoolConfig.setMinIdle(0);
jedisPoolConfig.setMaxWait(Duration.ofMillis(200));
jedisPoll = new JedisPool(jedisPoolConfig, "123.207.22.15", 6379,1000,"Ljj20010315_");
}
public static Jedis getJedis() {
return jedisPoll.getResource();
}
}

在连接池工具类创建完成之后,在测试类中进行调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@BeforeEach
void setUp() {
// 使用连接池,连接Redis服务器,不需要new Jedis对象了
jedis = jedisConnectionFactory.getJedis();
jedis.select(1);
}

@Test
void test() {
//...数据库操作
}

@AfterEach
void tearDown() {
//关闭链接
if(jedis != null) {
jedis.close();
}
}

使用连接池关闭链接后,并不会真正的关闭链接,而是把资源归还连接池。

链接池的 close() 方法重写了,当具有连接池的时候:

if (dataSource != null)

直接把资源归还给连接池:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public void close() {
if (dataSource != null) {
Pool<Jedis> pool = this.dataSource;
this.dataSource = null;
if (isBroken()) {
pool.returnBrokenResource(this);
} else {
pool.returnResource(this);
}
} else {
connection.close();
}
}

SpringDataRedis

SpringData是Spring中数据操作的模块,包含着对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis。

SpringDataRedis的特性

  1. 提供了对不同Java Redis客户端的整合(Lettuce和Jedis)
  2. 提供了RedisTemplate统一API来操作Redis
  3. 支持Redis的发布订阅模型
  4. 支持Redis哨兵和Redis集群
  5. 支持基于Lettuce的响应式编程
  6. 支持基于JDK、JSON、字符串、Spring对象的数据序列化和反序列化
  7. 支持基于Redis的JDKCollection实现

SpringDataRedis的使用

  1. 在maven的pom文件中引入sping-boot-starter-data-redis的依赖。(在springboot的依赖引入界面中选择SpringDataRedis即可)在新版本的SpringDataRedis中是包含common-pool2的,但是我们还是可以在pom文件中手动引入common-pool2依赖。
  2. 在src.main.resources.application.yaml文件中写好配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
spring:
data:
redis:
host: 123.207.22.15
port: 6379
password: Ljj20010315_
database: 1
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
max-wait: 200ms
  1. 在类中注入依赖,直接使用:
1
2
3
4
5
6
7
8
9
10
11
class SpringdataReidsDemoApplicationTests {
@Autowired
private RedisTemplate redisTemplate;

@Test
void testString() {
redisTemplate.opsForValue().set("price",21);
Object price = redisTemplate.opsForValue().get("price");
System.out.println(price);
}
}

RedisTemplate的序列化

当我们使用RedisTemplate对redis库进行set操作的时候,他会将我们传入的数据转化成序列化对象进行存储。

这是SpringDataRedis的特殊功能,它可以保存任何对象,自动进行序列化和反序列化。

当我们调用RedisTemplate的set方法的时候,传的参数是一个Object类的对象。