摘要
Redis官方文档:https://redis.io/documentation (opens new window)
Jedis 官方地址:https://github.com/redis/jedis (opens new window)
Lettuce 官方地址:
Redisson 官方地址:
# 一:前言
# 二:Jedis
# 2.1 引用
在 Maven 项目中添加 Jedis
依赖包,相关版本号可以查 Maven 仓库 (opens new window)
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.0.2</version>
</dependency>
2
3
4
5
# 2.2 连接
import redis.clients.jedis.Jedis;
/**
* Jedis 简单测试
*/
public class JedisMain {
public static void main(String[] args) {
// 1.构造一个 Jedis 对象
Jedis jedis = new Jedis("192.168.214.131", 6379);
// 2.密码认证
jedis.auth("1472");
// 3.测试是否连接成功
String ping = jedis.ping();
// 4.返回 pong 表示连接成功
System.out.println(ping);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 2.3 连接池
使用 Jedis 对象来操作 redis 时,每次操作都需要新建/关闭 TCP 连接,连接资源开销很高,同时 Jedis 对象的个数不受限制,在极端情况下可能会造成连接泄漏,同时 Jedis 存在多线程不安全的问题。
为什么说 Jedis 线程不安全,更加详细的原因可以访问这个地址https://www.cnblogs.com/gxyandwmm/p/13485226.html
!
所以我们需要将 Jedis 交给线程池来管理,使用 Jedis 对象时,从连接池获取 Jedis,使用完成之后,再还给连接池。
在使用之前,需要添加 common-pool
线程池依赖包,相关版本号可以查 Maven 仓库 (opens new window)
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
</dependency>
2
3
4
5
创建一个简单的使用线程池测试用例。
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
/**
* 线程池简单测试
*/
public class JedisMain2 {
public static void main(String[] args) {
// 1. 构造一个 Jedis 连接池
JedisPool pool = new JedisPool("192.168.214.131", 6379);
// 2. 从连接池中获取一个 Jedis 连接
Jedis jedis = pool.getResource();
jedis.auth("1472");
// 3. Jedis 操作
String ping = jedis.ping();
System.out.println(ping);
// 4. 归还连接
jedis.close();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
实际开发过程中,初始化线程池 JedisPool
及其相关配置
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class RedisPoolUtils {
private static JedisPool jedisPool = null;
/**
* redis 服务器地址
*/
private final static String addr = "192.168.214.131";
/**
* redis 服务器端口
*/
private final static int port = 6379;
/**
* redis 服务器密码
*/
private final static String auth = "1472";
static {
try {
JedisPoolConfig config = new JedisPoolConfig();
// 连接耗尽时是否阻塞, false 报异常,ture 阻塞直到超时, 默认 true
config.setBlockWhenExhausted(true);
// 设置的逐出策略类名, 默认 DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数)
config.setEvictionPolicyClassName("org.apache.commons.pool2.impl.DefaultEvictionPolicy");
// 是否启用pool的jmx管理功能, 默认 true
config.setJmxEnabled(true);
// MBean ObjectName = new ObjectName("org.apache.commons.pool2:type=GenericObjectPool,name=" + "pool" + i);
// 默认为"pool"
config.setJmxNamePrefix("pool");
// 是否启用后进先出, 默认 true
config.setLifo(true);
// 最大空闲连接数, 默认8个
config.setMaxIdle(8);
// 最大连接数, 默认8个
config.setMaxTotal(8);
// 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted)
// 如果超时就抛异常,小于零:阻塞不确定的时间,默认-1
config.setMaxWaitMillis(-1);
// 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
config.setMinEvictableIdleTimeMillis(1800000);
// 最小空闲连接数, 默认0
config.setMinIdle(0);
// 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
config.setNumTestsPerEvictionRun(3);
// 对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断(默认逐出策略)
config.setSoftMinEvictableIdleTimeMillis(1800000);
// 在获取连接的时候检查有效性, 默认false
config.setTestOnBorrow(false);
// 在空闲时检查有效性, 默认false
config.setTestWhileIdle(false);
// 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
config.setTimeBetweenEvictionRunsMillis(-1);
jedisPool = new JedisPool(config, addr, port, 3000, auth);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取 Jedis 资源
*
* @return Jedis 实例
*/
public static Jedis getJedis() {
if (jedisPool != null) {
return jedisPool.getResource();
}
return null;
}
/**
* 释放Jedis资源
*/
public static void close(final Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
}
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
简单测试
import redis.clients.jedis.Jedis;
/**
* 自定义线程池配置 测试
*/
public class JedisMain3 {
public static void main(String[] args) {
//获取 jedis 客户端
Jedis jedis = RedisPoolUtils.getJedis();
System.out.println("清空数据:" + jedis.flushDB());
System.out.println("设置新键值对[hello world]:" + jedis.set("hello", "world"));
System.out.println("获取键 hello 的值:" + jedis.get("hello"));
RedisPoolUtils.close(jedis);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2.4 全局命令
由于 Jedis 中的 API 和 Redis 的命令高度一致,所以,Jedis 中的方法见名知意,直接使用即可。
import redis.clients.jedis.Jedis;
import java.util.Set;
/**
* redis 全局操作命令 测试
*/
public class OverAllMain {
public static void main(String[] args) {
//获取 jedis 客户端
Jedis jedis = RedisPoolUtils.getJedis();
System.out.println("清空数据:" + jedis.flushDB());
jedis.mset("hello", "world", "java", "redis", "a", "1", "b", "2", "c", "cc");
Set<String> keys = jedis.keys("*");
System.out.println("keys *:" + keys);
System.out.println("键总数:" + jedis.dbSize());
System.out.println("键 hello 是否存在:" + jedis.exists("hello"));
System.out.println("删除键 hello:" + jedis.del("hello"));
System.out.println("设置键 java 的过期时间为5s:" + jedis.expire("java", 5L));
System.out.println("查看键 java 的剩余过期时间:" + jedis.ttl("java") + " 秒");
System.out.println("查看键 java 的剩余过期时间:" + jedis.pttl("java") + " 毫秒");
System.out.println("清除键 java 的过期时间:" + jedis.persist("java"));
System.out.println("查看键 java 的过期时间:" + jedis.ttl("java"));
System.out.println("查看键 java 的数据结构:" + jedis.type("java"));
System.out.println("查看键 java 的内部编码:" + jedis.objectEncoding("java"));
System.out.println("重命名键 java:" + jedis.rename("java", "java2"));
System.out.println("重命名键 a(重名):" + jedis.renamenx("a", "c"));
System.out.println("随机返回一个键:" + jedis.randomKey());
RedisPoolUtils.close(jedis);
}
}
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
# 2.5 string
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
/**
* redis String类型操作 测试
*/
public class StringMain {
public static void main(String[] args) {
Jedis jedis = RedisPoolUtils.getJedis();
// 常用命令
System.out.println("======================= 常用命令 =======================");
System.out.println("清空数据:" + jedis.flushDB());
System.out.println("设置新键值对[hello world]:" + jedis.set("hello", "world"));
System.out.println("设置 ex:" + jedis.set("name", "ccj", new SetParams().ex(100)));
System.out.println("设置 ex:" + jedis.setex("name", 100, "ccj"));
System.out.println("设置 px:" + jedis.set("name", "ccj", new SetParams().px(100)));
System.out.println("设置 nx:" + jedis.set("n1", "c1", new SetParams().nx()));
System.out.println("设置 nx:" + jedis.setnx("n1", "c1"));
System.out.println("设置 xx:" + jedis.set("n1", "c1", new SetParams().xx()));
System.out.println("获取键 hello 的值:" + jedis.get("hello"));
System.out.println("获取不存在的键 not_exist_key 的值:" + jedis.get("not_exist_key"));
System.out.println("批量设置:" + jedis.mset("a", "1", "b", "2", "c", "cc"));
System.out.println("批量获取:" + jedis.mget("a", "b", "c", "d"));
System.out.println("自增(数字):" + jedis.incr("number"));
// 会抛出 redis.clients.jedis.exceptions.JedisDataException: ERR value is not an integer or out of range 异常
// System.out.println("自增(非数字):" + jedis.incr("c"));
System.out.println("自增指定数字:" + jedis.incrBy("number", 3));
System.out.println("自增指定浮点数:" + jedis.incrByFloat("number2", 3));
System.out.println("自减(数字):" + jedis.decr("number"));
System.out.println("自减指定数字:" + jedis.decrBy("number", 2));
// 不常用命令
System.out.println("======================= 不常用命令 =======================");
System.out.println("追加值:" + jedis.append("hello", "java"));
System.out.println("获取键 hello 的值:" + jedis.get("hello"));
System.out.println("获取键 hello 的字符串长度:" + jedis.strlen("hello"));
System.out.println("设置键 hello 的新值并返回原值:" + jedis.getSet("hello", "redis"));
System.out.println("设置键 hello 设置指定位置开始的字符:" + jedis.setrange("hello", 0, "b"));
System.out.println("获取键 hello 的值:" + jedis.get("hello"));
System.out.println("获取部分字符串:" + jedis.getrange("hello", 0, 1));
RedisPoolUtils.close(jedis);
}
}
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
# 2.6 hash
import redis.clients.jedis.Jedis;
import java.util.HashMap;
import java.util.Map;
/**
* redis hash(哈希)类型操作 测试
*/
public class HashMain {
public static void main(String[] args) {
Jedis jedis = RedisPoolUtils.getJedis();
System.out.println("清空数据:" + jedis.flushDB());
System.out.println("设置新哈希值键值对[name tom]:" + jedis.hset("user:1", "name", "tom"));
System.out.println("设置field nx:" + jedis.hsetnx("user:1", "name", "tom"));
System.out.println("获取键 name 的值:" + jedis.hget("user:1", "name"));
Map<String, String> map = new HashMap<>();
map.put("a", "1");
map.put("b", "2");
map.put("c", "cc");
map.put("city", "gz");
System.out.println("批量设置:" + jedis.hmset("user:1", map));
System.out.println("计算field个数:" + jedis.hlen("user:1"));
System.out.println("批量获取:" + jedis.hmget("user:1", "a", "c", "d"));
System.out.println("删除field:" + jedis.hdel("user:1", "c"));
System.out.println("判断field city 是否存在:" + jedis.hexists("user:1", "city"));
System.out.println("获取所有field:" + jedis.hkeys("user:1"));
System.out.println("获取所有Value:" + jedis.hvals("user:1"));
System.out.println("获取所有field-value:" + jedis.hgetAll("user:1"));
System.out.println("自增指定数字:" + jedis.hincrBy("user:1", "number", 3));
System.out.println("自增指定浮点数:" + jedis.hincrByFloat("user:1", "number", 3));
System.out.println("计算field name 值的字符串长度:" + jedis.hstrlen("user:1", "name"));
RedisPoolUtils.close(jedis);
}
}
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
# 2.7 list
import redis.clients.jedis.Jedis;
import redis.clients.jedis.args.ListPosition;
/**
* redis list(列表)类型操作 测试
*/
public class ListMain {
public static void main(String[] args) {
Jedis jedis = RedisPoolUtils.getJedis();
System.out.println("清空数据:" + jedis.flushDB());
System.out.println("从右边插入元素:" + jedis.rpush("listkey", "c", "b", "a"));
System.out.println("从左边插入元素:" + jedis.lpush("listkey", "a", "b", "c"));
System.out.println("从左到右遍历:" + jedis.lrange("listkey", 0, -1));
System.out.println("向元素b前插入元素:" + jedis.linsert("listkey", ListPosition.BEFORE, "b", "java"));
System.out.println("从左到右遍历:" + jedis.lrange("listkey", 0, -1));
System.out.println("获取列表下标为2的元素:" + jedis.lindex("listkey", 2));
System.out.println("获取列表长度:" + jedis.llen("listkey"));
System.out.println("从列表左侧弹出元素:" + jedis.lpop("listkey"));
System.out.println("从左到右遍历:" + jedis.lrange("listkey", 0, -1));
System.out.println("从列表右侧弹出元素:" + jedis.rpop("listkey"));
System.out.println("从左到右遍历:" + jedis.lrange("listkey", 0, -1));
System.out.println("删除指定元素a:" + jedis.lrem("listkey", 0, "a"));
System.out.println("从左到右遍历:" + jedis.lrange("listkey", 0, -1));
System.out.println("按照索引范围[1-3]修剪列表:" + jedis.ltrim("listkey", 1, 3));
System.out.println("从左到右遍历:" + jedis.lrange("listkey", 0, -1));
System.out.println("修改指定索引下标2的元素:" + jedis.lset("listkey", 2, "python"));
System.out.println("从左到右遍历:" + jedis.lrange("listkey", 0, -1));
RedisPoolUtils.close(jedis);
}
}
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
# 2.8 set
import redis.clients.jedis.Jedis;
/**
* redis Set(集合)类型操作 测试
*/
public class SetMain {
public static void main(String[] args) {
Jedis jedis = RedisPoolUtils.getJedis();
// 集合内操作
System.out.println("======================= 集合内操作 =======================");
System.out.println("清空数据:" + jedis.flushDB());
System.out.println("添加元素:" + jedis.sadd("myset", "a", "b", "c", "d", "e", "f", "g"));
System.out.println("获取所有元素:" + jedis.smembers("myset"));
System.out.println("删除元素a和b:" + jedis.srem("myset", "a", "b"));
System.out.println("获取所有元素:" + jedis.smembers("myset"));
System.out.println("计算元素个数:" + jedis.scard("myset"));
System.out.println("判断元素c是否在集合中:" + jedis.sismember("myset", "c"));
System.out.println("随机从集合返回2个元素:" + jedis.srandmember("myset", 2));
System.out.println("计算元素个数:" + jedis.scard("myset"));
System.out.println("从集合随机弹出元素:" + jedis.spop("myset"));
System.out.println("计算元素个数:" + jedis.scard("myset"));
// 集合间操作
System.out.println("======================= 集合间操作 =======================");
jedis.sadd("user:1:follow", "it", "music", "his", "sports");
jedis.sadd("user:2:follow", "it", "news", "ent", "sports");
System.out.println("交集:" + jedis.sinter("user:1:follow", "user:2:follow"));
System.out.println("并集:" + jedis.sunion("user:1:follow", "user:2:follow"));
System.out.println("差集:" + jedis.sdiff("user:1:follow", "user:2:follow"));
// 保存交集
jedis.sinterstore("user:1_2:inter", "user:1:follow", "user:2:follow");
System.out.println("交集 user:1_2:inter 数据类型:" + jedis.type("user:1_2:inter"));
System.out.println("获取所有元素:" + jedis.smembers("user:1_2:inter"));
RedisPoolUtils.close(jedis);
}
}
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
# 2.9 zset
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.ZAddParams;
import redis.clients.jedis.params.ZParams;
import java.util.HashMap;
import java.util.Map;
/**
* redis zset(有序集合)类型操作 测试
*/
public class ZsetMain {
public static void main(String[] args) {
Jedis jedis = RedisPoolUtils.getJedis();
// 有序集合内操作
System.out.println("======================= 有序集合内操作 =======================");
System.out.println("清空数据:" + jedis.flushDB());
System.out.println("添加元素:" + jedis.zadd("user:ranking", 1, "kris"));
Map<String, Double> members = new HashMap<>();
members.put("mike", 91d);
members.put("frank", 200d);
members.put("tim", 220d);
members.put("martin", 250d);
System.out.println("批量添加元素:" + jedis.zadd("user:ranking", members));
System.out.println("新增元素(添加参数):" + jedis.zadd("user:ranking", 150, "jack", new ZAddParams().nx().ch()));
System.out.println("计算成员个数:" + jedis.zcard("user:ranking"));
System.out.println("成员jack的分数:" + jedis.zscore("user:ranking", "jack"));
System.out.println("计算成员jack的排名(分数从低到高):" + jedis.zrank("user:ranking", "jack"));
System.out.println("计算成员jack的排名(分数从高到低):" + jedis.zrevrank("user:ranking", "jack"));
System.out.println("删除成员mike:" + jedis.zrem("user:ranking", "mike"));
System.out.println("成员jack分数增加10:" + jedis.zincrby("user:ranking", 10, "jack"));
System.out.println("排名靠后两位:" + jedis.zrange("user:ranking", 0, 1));
System.out.println("排名靠前两位:" + jedis.zrevrange("user:ranking", 0, 1));
System.out.println("排名靠前两位(同时返回分数):" + jedis.zrevrangeWithScores("user:ranking", 0, 1));
System.out.println("返回指定分数范围(160-230)的成员(分数从低到高):" + jedis.zrangeByScore("user:ranking", 160, 230));
System.out.println("返回指定分数范围(160-230)的成员(分数从高到低):" + jedis.zrevrangeByScore("user:ranking", 230, 160));
System.out.println("200分以上成员:" + jedis.zrangeByScoreWithScores("user:ranking", "(200", "+inf"));
System.out.println("返回指定分数范围成(200-300)员个数:" + jedis.zcount("user:ranking", 200, 300));
System.out.println("删除排名靠后两位:" + jedis.zremrangeByRank("user:ranking", 0, 1));
System.out.println("删除200分以上成员:" + jedis.zremrangeByScore("user:ranking", "(200", "+inf"));
// 有序集合间操作
System.out.println("======================= 有序集合间操作 =======================");
Map<String, Double> members1 = new HashMap<>();
members1.put("kris", 1d);
members1.put("mike", 91d);
members1.put("frank", 200d);
members1.put("tim", 220d);
members1.put("martin", 250d);
members1.put("tom", 251d);
Map<String, Double> members2 = new HashMap<>();
members2.put("james", 8d);
members2.put("mike", 77d);
members2.put("martin", 625d);
members2.put("tom", 888d);
jedis.zadd("user:ranking:1", members1);
jedis.zadd("user:ranking:2", members2);
ZParams zParams = new ZParams();
zParams.aggregate(ZParams.Aggregate.MAX);
zParams.weights(1, 0.5);
System.out.println("交集:" + jedis.zinterstore("user:ranking:1_inter_2", zParams, "user:ranking:1", "user:ranking:2"));
System.out.println("遍历:" + jedis.zrangeWithScores("user:ranking:1_inter_2", 0, -1));
System.out.println("并集:" + jedis.zunionstore("user:ranking:1_union_2", "user:ranking:1", "user:ranking:2"));
System.out.println("遍历:" + jedis.zrangeWithScores("user:ranking:1_union_2", 0, -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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# 2.10 scan
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.ScanParams;
import redis.clients.jedis.resps.ScanResult;
import java.util.List;
/**
* redis scan操作 测试
*/
public class ScanMain {
public static void main(String[] args) {
Jedis jedis = RedisPoolUtils.getJedis();
System.out.println("清空数据:" + jedis.flushDB());
// 插入临时数据
for (int i = 0; i < 1234; i++) {
jedis.set(i + "", i + "");
}
// 游标初始值为0
String cursor = ScanParams.SCAN_POINTER_START;
String key = "1*";
ScanParams scanParams = new ScanParams();
scanParams.match(key);
scanParams.count(15);
do {
// 使用scan命令获取数据,使用cursor游标记录位置,下次循环使用
ScanResult<String> scanResult = jedis.scan(cursor, scanParams);
cursor = scanResult.getCursor();// 返回0 说明遍历完成
List<String> list = scanResult.getResult();
System.out.println("========获取 " + list.size() + " 条数据, cursor:" + cursor + "========");
for (String member : list) {
System.out.print(member + " ");
}
System.out.println();
} while (!"0".equals(cursor));
RedisPoolUtils.close(jedis);
}
}
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
# 2.11 哨兵
哨兵模式:对 redis 服务器进行监控,如果有宕机的,就从备机里面选一个出来作为主机,实现自动切换。
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
import java.util.HashSet;
import java.util.Set;
/**
* redis 哨兵 测试
*/
public class SentinelMain {
private static Jedis jedis;
static {
JedisPoolConfig config = new JedisPoolConfig();
// 最大空闲连接数, 默认8个
config.setMaxIdle(8);
// 最大连接数, 默认8个
config.setMaxTotal(8);
// 最小空闲连接数, 默认0
config.setMinIdle(0);
// 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常,小于零:阻塞不确定的时间,默认-1
config.setMaxWaitMillis(3000);
// 在获取连接的时候检查有效性,表示取出的redis对象可用, 默认false
config.setTestOnBorrow(true);
// redis服务器列表
Set<String> sentinels = new HashSet<>();
sentinels.add(new HostAndPort("172.17.0.5", 26379).toString());
sentinels.add(new HostAndPort("172.17.0.6", 26379).toString());
sentinels.add(new HostAndPort("172.17.0.7", 26379).toString());
// 初始化连接池
try (JedisSentinelPool jedisSentinelPool = new JedisSentinelPool("redis-master", sentinels, config, "qazwsx123edc")) {
// 从池中获取一个Jedis对象
jedis = jedisSentinelPool.getResource();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println("清空数据:" + jedis.flushDB());
System.out.println("设置新键值对[hello world]:" + jedis.set("hello", "world"));
System.out.println("获取键 hello 的值:" + jedis.get("hello"));
}
}
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
51
由于部署问题,这里的 java 代码放在了 SpringBoot 项目中,部署在 Linux 测试。
# 2.12 集群
Cluster 模式:将数据进行分片存储,避免全部节点数据都一样,浪费空间。
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.*;
import java.util.HashSet;
import java.util.Set;
/**
* redis 集群 测试
*/
public class ClusterMain {
private static JedisCluster jedisCluster;
static {
try {
GenericObjectPoolConfig<Connection> config = new GenericObjectPoolConfig<>();
// 最大空闲连接数, 默认8个
config.setMaxIdle(8);
// 最大连接数, 默认8个
config.setMaxTotal(8);
// 最小空闲连接数, 默认0
config.setMinIdle(0);
// 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,默认-1
config.setMaxWaitMillis(3000);
// 在获取连接的时候检查有效性,表示取出的redis对象可用, 默认false
config.setTestOnBorrow(true);
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("192.168.214.131", 6383));
nodes.add(new HostAndPort("192.168.214.131", 6384));
nodes.add(new HostAndPort("192.168.214.131", 6385));
nodes.add(new HostAndPort("192.168.214.131", 6386));
nodes.add(new HostAndPort("192.168.214.131", 6387));
nodes.add(new HostAndPort("192.168.214.131", 6388));
jedisCluster = new JedisCluster(nodes, 1000, 1000, 5, "qazwsx123edc", config);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println("清空数据:" + jedisCluster.flushDB());
System.out.println("设置新键值对[hello world]:" + jedisCluster.set("hello", "world"));
System.out.println("获取键 hello 的值:" + jedisCluster.get("hello"));
}
}
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
# 2.13 小结
优点:
- 比较全面的提供了 Redis 的操作特性,也就是说你能用 redis 命令操作的,Jedis 包都也给你封装好了,直接使用即可;
- 使用广泛,易上手。
缺点:
- Jedis 客户端实例不是线程安全的,需要借助连接池来管理和使用 Jedis;
- 使用阻塞的I/O,且其方法调用都是同步的,程序流需要等到 sockets 处理完 I/O 才能执行,不支持异步。
# 三:Lettuce
spring-data-redis
的驱动包在某个版本之后底层替换为 Lettuce
Lettuce
是一个高性能基于 Java
编写的 Redis
驱动框架,底层集成了 Project Reactor
提供天然的反应式编程,通信框架集成了 Netty
使用了非阻塞 IO
,5.x
版本之后融合了 JDK1.8
的异步编程特性,在保证高性能的同时提供了十分丰富易用的 API
,5.1
版本的新特性如下:
- 支持
Redis
的新增命令ZPOPMIN, ZPOPMAX, BZPOPMIN, BZPOPMAX
; - 支持通过
Brave
模块跟踪Redis
命令执行; - 支持
Redis Streams
; - 支持异步的主从连接;
- 支持异步连接池;
- 新增命令最多执行一次模式(禁止自动重连);
- 全局命令超时设置(对异步和反应式命令也有效);
- ... ... 等等
# 3.1 引用
在 Maven 项目中添加 Lettuce
依赖包,相关版本号可以查 Maven 仓库 (opens new window)
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.2.6.RELEASE</version>
</dependency>
2
3
4
5
# 3.2 连接
Not found: D:\blog\ccj-blog/docs/views/notes/redis/file/java/lettuce/JedisMain.java
# 四:Redisson
# 五:RedisTemplate
# 六:参考文献
- 《Redis深度历险:核心原理和应用实践 - 钱文品》
- 《Redis 开发与运维 - 付磊、张益军》
- 官方文档 (opens new window)
- 【进阶篇】Redis实战之Jedis使用技巧详解 (opens new window)
- Redis高级客户端Lettuce详解 (opens new window)