Redis进阶

郎家岭伯爵 2023年04月03日 621次浏览

前言

本文将介绍 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

  1. 添加 Redis 依赖。
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. 在 application.properties 文件中添加 Redis 的配置信息。
# Redis服务器地址
spring.redis.host=localhost
# Rediss数据库索引(默认为0)
spring.redis.database=0
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
  1. 测试类测试代码。
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

RedisTemplateStringRedisTemplate 都是 Spring Data Redis 提供的模板类,可以对 Redis 进行操作,后者针对键值对都是 String 类型的数据,前者可以是任何类型的对象。

RedisTemplateStringRedisTemplate 除了提供 opsForValue 方法来操作字符串之外,还提供了以下方法:

  • opsForList:操作 list
  • opsForSet:操作 set
  • opsForZSet:操作有序 set
  • opsForHash:操作 hash

SpringBoot连接池连接Redis

Redis 是基于内存的数据库,本来是为了提高程序性能的,但如果不使用 Redis 连接池的话,建立连接、断开连接就需要消耗大量的时间。

用了连接池,就可以实现在客户端建立多个连接,需要的时候从连接池拿,用完了再放回去,这样就节省了连接建立、断开的时间。

要使用连接池,我们得先了解 Redis 的客户端,常用的有两种:JedisLettuce

  • Jedis:Spring Boot 1.5.x 版本时默认的 Redis 客户端,实现上是直接连接 Redis Server,如果在多线程环境下是非线程安全的,这时候要使用连接池为每个 jedis 实例增加物理连接;
  • Lettuce:Spring Boot 2.x 版本后默认的 Redis 客户端,基于 Netty 实现,连接实例可以在多个线程间并发访问,一个连接实例不够的情况下也可以按需要增加连接实例。

Jedis连接池

  1. 在 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>
  1. 修改 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
  1. 启动服务后,观察 redisTemplateclientConfiguration 节点,可以看到它的值已经变成 DefaultJedisClientConfiguration 对象了。

如果没有启用连接池的话,是看不到 poolConfig 信息的:

也可以不配置 Jedis 客户端的连接池,走默认的连接池配置。因为 Jedis 客户端默认增加了连接池的依赖包,在 pom.xml 文件中点开 Jedis 客户端依赖可以查看到。

Lettuce连接池(推荐)

  1. 在 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>
  1. 在 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
  1. 重新启动服务,在 redisTemplate 处打上断点,debug 模式下可以看到连接池的配置信息(redisConnectionFactory→clientConfiguration→poolConfig)。如下图所示:

至此,我们完成了使用连接池来操作 Redis。

总结

本文介绍了 Redis 的一些进阶操作。