前言
本文将介绍 Redis 进阶的一些操作。
实现
Redis 安装已在《Redis入门》一文中详细说明,本文不再赘述。
客户端工具
介绍一款 Redis 客户端工具——AnotherRedisDesktopManager,支持 Windows、macOS 和 Linux,性能出众,可以轻松加载海量键值。
数据结构
Redis 支持五种数据类型:String(字符串)
,Hash(哈希)
,List(列表)
,Set(集合)
及 Zset(Sorted Set:有序集合)
。
接下来我们在 AnotherRedisDesktopManager 工具里操作一下这几种数据类型。
字符串(String)
Redis 中最基本的数据结构之一,可以存储任何类型的数据,包括二进制数据,最大长度为512MB。
文本命令:
> 127.0.0.1@6379 connected!
# 设置 key 为 user,value为“郎家岭伯爵”
> set user '郎家岭伯爵'
OK
# 获取
> get user
郎家岭伯爵
# 重新设置 key 对应的 value
> set user '郎家岭伯爵1'
OK
# 重新获取
> get user
郎家岭伯爵1
# 判断 key 是否存在。存在为1,不存在为0
> exists user
1
# 删除指定的 key
> del user
1
# key 不存在,返回0
> exists user
0
哈希(Hash)
哈希表是一个键值对集合,其中键和值都是字符串类型。哈希表非常适合存储对象,因为它可以将一个对象的各个属性存储在不同的哈希表字段中。
文本命令:
# 清空数据库
> flushdb
OK
# 创建 hash,key 为 user_hset,字段为 user1,值为 langjialing1
> hset user_hset user1 langjialing1
1
> hset user_hset user2 langjialing2
1
# 字段长度
> hlen user_hset
2
# 所有字段
> hkeys user_hset
user1
user2
# 所有值
> hvals user_hset
langjialing1
langjialing2
# 字段 user1 的值
> hget user_hset user1
langjialing1
# 获取 key 为 user_hset 的所有的字段和值
> hgetall user_hset
user1
langjialing1
user2
langjialing2
# 增加一个字段为 user,值为“郎家岭伯爵”
> hset user_hset user '郎家岭伯爵'
1
# 获取 key 为 user_hset 的所有的字段和值
> hgetall user_hset
user1
langjialing1
user2
langjialing2
user
郎家岭伯爵
# 更新字段
> hset user_hset user 'LANGJIALING'
0
> hgetall user_hset
user1
langjialing1
user2
langjialing2
user
LANGJIALING
# 删除字段
> hdel user_hset user1
1
> hgetall user_hset
user2
langjialing2
user
LANGJIALING
列表(List)
Redis 列表是一个有序的字符串列表,可以在列表的两端添加或删除元素。列表可以用于实现队列和栈等数据结构。
文本命令:
# 添加 key 为 user_list,value 为 langjialing1 langjialing2 langjialing3 的集合
> lpush user_list langjialing1 langjialing2 langjialing3
3
# 查询 key 为 user_list 的所有 value
> lrange user_list 0 -1
langjialing3
langjialing2
langjialing1
# 头部添加
> lpush user_list '郎家岭伯爵'
4
> lrange user_list 0 -1
郎家岭伯爵
langjialing3
langjialing2
langjialing1
# 尾部添加
> rpush user_list '郎家岭伯爵0'
5
> lrange user_list 0 -1
郎家岭伯爵
langjialing3
langjialing2
langjialing1
郎家岭伯爵0
# 更新 index 为0的值
> lset user_list 0 LANGJIALINGBOJUE
OK
> lrange user_list 0 -1
LANGJIALINGBOJUE
langjialing3
langjialing2
langjialing1
郎家岭伯爵0
> lrange user_list 0 -1
LANGJIALINGBOJUE
langjialing3
langjialing2
langjialing1
郎家岭伯爵0
# 删除 index 为0的值
> lrem user_list 0 LANGJIALINGBOJUE
1
> lrange user_list 0 -1
langjialing3
langjialing2
langjialing1
郎家岭伯爵0
关于 lrange key start stop
命令,其中,key 是列表的键名,start 和 stop 是要获取的元素的起始位置和结束位置,起始位置从0开始计数。
例如,要获取列表中前5个元素,可以执行以下命令:
lrange user_list 0 4
如果要获取列表中的所有元素,则可以执行以下命令:
lrange mylist 0 -1
其中,0表示起始位置,-1表示结束位置,表示获取所有元素。这个命令可以用于一次性获取整个列表的所有元素。
集合(Set)
集合是一个无序的字符串集合,不允许重复元素。集合支持交集、并集和差集等操作。
文本命令:
# 添加 key 为 user_set,value 为 langjialing1 langjialing2 langjialing3 的集合
> sadd user_set langjialing1 langjialing2 langjialing3
3
# 查询集合中的所有元素
> smembers user_set
langjialing3
langjialing2
langjialing1
# 删除 value 为 langjialing3 的元素
> srem user_set langjialing3
1
> smembers user_set
langjialing2
langjialing1
# 添加元素
> sadd user_set '郎家岭伯爵'
1
> smembers user_set
郎家岭伯爵
langjialing2
langjialing1
有序集合(Sorted Set)
有序集合是一个有序的字符串集合,每个元素都关联着一个分数,可以根据分数对元素进行排序。有序集合通常用于实现排行榜等应用。
关于有序集合(Sorted Set)中的分数,每个元素都关联着一个分数(score),可以根据分数对元素进行排序。在有序集合中,分数是一个浮点型的数值,用来表示元素的权重或者优先级。
有序集合中的元素是唯一的,但是分数可以重复。当多个元素的分数相同时,它们会按照字典序进行排序。因此,在使用有序集合时,需要根据具体的业务需求,合理地设置元素的分数,以便在排序时得到正确的结果。
有序集合的应用场景非常广泛,例如可以用来实现排行榜、计数器、带权重的队列等功能。
文本命令:
# 添加 key 为 user_zset 分数为1值为langjialing1,分数为2值为langjialing2,分数为3值为langjialing3
> zadd user_zset 1 langjialing1 2 langjialing2 3 langjialing3
3
# 查询所有元素
> zrange user_zset 0 -1
langjialing1
langjialing2
langjialing3
# 反转所有元素
> zrevrange user_zset 0 -1
langjialing3
langjialing2
langjialing1
# 查询元素langjialing2的分数
> zscore user_zset langjialing2
2
至此,我们完成了 Redis 的5种基本数据结构的简单操作。
关于 Redis 的5种基本数据结构,我们简单总结如下:
- 字符串(String) 是 Redis 最基本的数据类型,存储一个键值对。
- 哈希(Hash) 是一个键值对集合,值可以看成是一个 Map。
- 列表(List) 是一个简单的字符串列表,按照插入顺序排序。
- 集合(Set) 是 String 类型的无序集合,不允许有重复的元素。
- 有序集合(Sorted Set) 是 String 类型的有序集合,不允许有重复的元素。
SpringBoot直连Redis
- 添加 Redis 依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 在 application.properties 文件中添加 Redis 的配置信息。
# Redis服务器地址
spring.redis.host=localhost
# Rediss数据库索引(默认为0)
spring.redis.database=0
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
- 测试类测试代码。
package com.langjialing.springbootredisdemo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@SpringBootTest
class SpringbootRedisDemoApplicationTests {
@Resource
private RedisTemplate redisTemplate;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Test
public void testRedis() {
// 添加
redisTemplate.opsForValue().set("name","郎家岭伯爵");
// 查询
System.out.println(redisTemplate.opsForValue().get("name"));
// 删除
redisTemplate.delete("name");
// 更新
redisTemplate.opsForValue().set("name","郎家岭伯爵0", 20, TimeUnit.SECONDS);
// 查询
System.out.println(redisTemplate.opsForValue().get("name"));
// 添加,并设置过期时间
stringRedisTemplate.opsForValue().set("name0", "郎家岭伯爵", 30, TimeUnit.SECONDS);
// 查询
System.out.println(stringRedisTemplate.opsForValue().get("name0"));
// 删除
stringRedisTemplate.delete("name0");
// 更新,并设置过期时间
stringRedisTemplate.opsForValue().set("name0","郎家岭伯爵1", 30, TimeUnit.SECONDS);
// 查询
System.out.println(stringRedisTemplate.opsForValue().get("name0"));
}
@Test
void Redis0(){
System.out.println(redisTemplate.opsForValue().get("name"));
// 根据key获取过期时间,并转换为指定时间单位
System.out.println(redisTemplate.getExpire("name", TimeUnit.SECONDS));
System.out.println(stringRedisTemplate.opsForValue().get("name0"));
// 根据key获取过期时间,并转换为指定时间单位
System.out.println(stringRedisTemplate.getExpire("name0", TimeUnit.SECONDS));
}
}
testRedis 测试类输出:
郎家岭伯爵
郎家岭伯爵0
郎家岭伯爵
郎家岭伯爵1
Redis0 测试类输出:
郎家岭伯爵0
9
郎家岭伯爵1
19
RedisTemplate
和 StringRedisTemplate
都是 Spring Data Redis
提供的模板类,可以对 Redis 进行操作,后者针对键值对都是 String 类型的数据,前者可以是任何类型的对象。
RedisTemplate
和 StringRedisTemplate
除了提供 opsForValue
方法来操作字符串之外,还提供了以下方法:
- opsForList:操作 list
- opsForSet:操作 set
- opsForZSet:操作有序 set
- opsForHash:操作 hash
SpringBoot连接池连接Redis
Redis 是基于内存的数据库,本来是为了提高程序性能的,但如果不使用 Redis 连接池的话,建立连接、断开连接就需要消耗大量的时间。
用了连接池,就可以实现在客户端建立多个连接,需要的时候从连接池拿,用完了再放回去,这样就节省了连接建立、断开的时间。
要使用连接池,我们得先了解 Redis 的客户端,常用的有两种:Jedis
和 Lettuce
。
Jedis
:Spring Boot 1.5.x 版本时默认的 Redis 客户端,实现上是直接连接 Redis Server,如果在多线程环境下是非线程安全的,这时候要使用连接池为每个 jedis 实例增加物理连接;Lettuce
:Spring Boot 2.x 版本后默认的 Redis 客户端,基于 Netty 实现,连接实例可以在多个线程间并发访问,一个连接实例不够的情况下也可以按需要增加连接实例。
Jedis连接池
- 在 pom.xml 文件中添加 Jedis 依赖,去除 Lettuce 默认依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
- 修改 application.properties,添加 Jedis 连接池配置。
# Redis服务器地址
spring.redis.host=localhost
# Rediss数据库索引(默认为0)
spring.redis.database=0
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数
spring.redis.jedis.pool.max-active=8
# 连接池最大空闲连接数
spring.redis.jedis.pool.max-idle=8
# 连接池最小空闲连接数
spring.redis.jedis.pool.min-idle=0
# 连接池最大阻塞等待时间,负值表示没有限制
spring.redis.jedis.pool.max-wait=-1ms
- 启动服务后,观察
redisTemplate
的clientConfiguration
节点,可以看到它的值已经变成DefaultJedisClientConfiguration
对象了。
如果没有启用连接池的话,是看不到 poolConfig 信息的:
也可以不配置 Jedis 客户端的连接池,走默认的连接池配置。因为 Jedis 客户端默认增加了连接池的依赖包,在 pom.xml 文件中点开 Jedis 客户端依赖可以查看到。
Lettuce连接池(推荐)
- 在 pom.xml 中导入依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
- 在 application.properties 中添加 Lettuce 配置。
# Redis服务器地址
spring.redis.host=localhost
# Rediss数据库索引(默认为0)
spring.redis.database=0
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数
spring.redis.lettuce.pool.max-active=8
# 连接池最大空闲连接数
spring.redis.lettuce.pool.max-idle=8
# 连接池最小空闲连接数
spring.redis.lettuce.pool.min-idle=0
# 连接池最大阻塞等待时间,负值表示没有限制
spring.redis.lettuce.pool.max-wait=-1ms
- 重新启动服务,在
redisTemplate
处打上断点,debug 模式下可以看到连接池的配置信息(redisConnectionFactory→clientConfiguration→poolConfig)。如下图所示:
至此,我们完成了使用连接池来操作 Redis。
总结
本文介绍了 Redis 的一些进阶操作。