一、Redis 概述

什么是 Reids

Reids,全称 Remote Dictionary Server,远程词典服务器,是一个基于内存的键值型 NoSQL 数据库。

知名的高性能内存 K/V 存储系统,因为它的高性能、通用性、易用性、功能强大,使得它成为后端开发中必不可少的中间件。

特点

  • 键值型,value 支持多种数据结构,功能丰富
  • 命令单线程,每个命令具备原子性
  • 低延迟,速度快(基于内存、IO 多路复用、良好的编码)
  • 支持数据持久化(定期从内存持久化到磁盘)
  • 支持主从集群、分片集群
  • 支持多语言客户端

二、SQL 和 NoSQL

SQL NoSQL
数据结构 结构化 非结构化
键值类型(Redis)、文档类型(MongoDB)、列类型(HBase)、Graph 类型(Neo4j)
数据关联 有关联的 无关联的
查询方式 SQL 查询 非 SQL
事务特性 ACID BASE
存储方式 磁盘 内存
扩展性 垂直 水平
使用场景 ① 数据结构固定
② 业务对数据的安全性、一致性要求较高
① 数据结构不固定
② 对一致性、安全性要求不高
③ 对性能要求较高

三、Redis 单机安装

基于 Linux 安装 Redis

第一步:安装 Redis 依赖

Redis 基于 C 语言编写,所以需要 gcc 依赖:

1
yum -install -y gcc ctl

第二步:上传安装包并压缩,这里我放在了 /usr/local 下

1
2
cd /usr/local
tar -zxvf 压缩包

第三步:运行编译命令

1
make && make install

不报错即安装成功,默认安装路径为 /usr/local/bin

1
2
3
4
[root@localhost01 bin]# pwd
/usr/local/bin
[root@localhost01 bin]# ls
redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-sentinel redis-server
  • redis-cli:命令行客户端
  • redis-server:服务端启动脚本
  • redis-sentinel:哨兵启动脚本

四、Redis 启动方式

启动方式:

  • 默认启动
  • 指定配置启动
  • 开机自启

默认启动

默认为 前台启动,会阻塞整个会话窗口。

1
redis-server

指定配置启动

修改 Redis 配置文件,Redis 根目录下的 redis.conf 文件:

1
2
3
4
5
6
7
8
9
# 备份
cp redis.conf redis.conf.bck

# 允许访问的地址(生产环境下不要设置为 0.0.0.0)
bind 0.0.0.0
# 守护进程,修改后可后台运行
daemonize yes
# 密码,设置后访问 Redis 必须输入密码
requirepass xxx

其他常见配置:

1
2
3
4
5
6
7
8
9
10
# 监听的端口
port 6379
# 工作目录,日志、持久化等文件保存在该目录
dir ./
# 数据库数量,默认有 16 个库,编号 0~15
database 16
# Redis 能够使用的最大内存
maxmemory 512mb
# 日志文件,默认为空
logfile ""

启动:

1
2
cd /user/local/redis
redis-server redis.conf

停止:

1
redis-cli -a password shutdown

开机自启

通过配置设置开机自启。

新建一个系统服务文件:

1
vi /etc/systemd/system/redis.service

内容如下:

1
2
3
4
5
6
7
8
9
10
11
[Unit]
Description=redis-server
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/bin/redis-server /usr/local/redis/redis.conf
PrivateTmp=true

[Install]
WantedBy=multi-user.target

重载系统服务:

1
systemctl daemon-reload

操作 Reids:

1
2
3
4
systemctl start redis
systemctl stop redis
systemctl restart redis
systemctl status redis

执行命令,实现开机自启:

1
systemctl enable redis

五、管理工具

命令行

安装后自带的命令行工具:redis-cli

使用方式:

1
redis-cli [option] [commands]
  • 常见 option
    • -h:指定要连接的 redis 节点的 ip,默认为 127.0.0.1
    • -p:指定要连接的 redis 节点的端口,默认为 6379
    • -a:指定 redis 的访问密码
      使用这个参数会提示不安全,可以连接之后使用 AUTH 指定
  • 常见 commands
    • ping:测试与 redis 服务端的连接,正常则返回 PONG

图形化界面

使用官方提供的 RedisInsight 工具。

安装后,Linux 服务器开放 6379 端口或关闭防火墙,就能从客户端连接我们的 Redis 数据库了。

六、常用命令

通用命令

  • KEYS:查看所有 key
  • DEL:删除 key
  • EXISTS:判断 key 是否存在
  • EXPIRE:给 key 设置有效期
  • TTL:查看 key 的剩余有效期

命令手册

  • 官网手册
  • 还可以在命令行,使用 help 命令查询

七、数据结构

基本类型

  • String
  • Hash
  • List
  • Set
  • SortedSet

特殊类型

  • GEO
  • BitMap
  • HyperLog

String

字符串类型,Redis 中最简单的存储类型。最大空间不能超过 512m。

value 是字符串,根据字符串分为:string、int、float。

KEY VALUE
project:user:1 {name:”tom”, age:18}
project:user:2 {…}

常用命令:

  • SET
  • GET
  • MSET:批量添加多个 String 类型的键值对
  • MGET:根据多个 key 获取多个 String 类型的 value
  • INCR:整型 key 自增 1
  • INCRBY:整型 key 自增并指定步长
  • INCRBYFLOAT:浮点型数字自增并指定步长
  • SETNX:添加一个 String 类型的键值对,前提是 key 不存在
  • SETEX:添加一个 String 类型的键值对,并指定有效期

key 的层级结构

Redis 中可以使用多个单词形成层级结构,多个单词间用冒号分隔,例如:

1
2
project:user:1
project:user:2

Hash

value 是无序字典,类似于 Java 中的 HashMap。

KEY field | value
hash name | tom
age | 21

常用命令:

  • HSET key filed value
  • HGET key filed
  • HMSET
  • HMGET
  • HGETALL
  • HKEYS
  • HVALS
  • HINCRBY
  • HSETNX

List

value 可以看作双向链表结构,类似于 Java 中的 LinkedList。

特征与 LinkedList 类似:

  • 有序
  • 元素可以重复
  • 插入删除快
  • 查询速度一般
KEY index | element
list 0 | name
1 | age

常用命令:

  • LPUSH key element …
  • LPOP key
  • RPUSH key element …
  • RPUP key
  • LRANGE key star end
  • BLPOP、BRPOP

Set

可以看作 value 为 null 的 HashMap,类似于 Java 中的 HashSet。

特征与 HashSet 类似:

  • 无序
  • 元素不可重复
  • 查找快
  • 支持交集、并集、差集等功能
KEY Member
set name
age

常用命令:

  • SADD key member …
  • SREM key member …
  • SCARD key
  • SISMEMBER key member
  • SMEMBERS
  • SINTER key1 key2:交集
  • SDIFF key1 key2:差集
  • SUNION key1 key2:并集

SortedSet

可排序的 set 集合,类似于 Java 中的 TreeSet(功能类似,底层数据结构差别很大)。

SortedSet 中的每个元素都带有一个 score 属性,可以基于 score 属性对元素排序。底层:跳表(SkipList) + hash 表。

特征:

  • 可排序
  • 元素不重复
  • 查询速度快
KEY Member | Score
sortedset age | 18

常用命令:

  • ZADD key score member
  • ZREM key member
  • ZSCORE key member:获取指定元素的 score 值
  • ZRANK key member
  • ZCARD key
  • ZCOUNT key min max
  • ZINCRBY key increment member
  • ZRANGE key min max
  • ZRANGEBYSCORE key min max
  • ZDIFF、ZINTER、ZUNION

八、Java 客户端

客户端 特点
Jedis 以 Redis 命令作为方法名,学习成本低,简单实用。但是 Jedis 实例是线程不安全的,多线程环境下需要基于连接池使用。
Lettuce 基于 Netty 实现,支持同步、异步、响应式编程方式,并且是线程安全的,支持 Redis 的哨兵模式、集群模式和管道模式。
Redisson 基于 Redis 实现的分布式、可伸缩的 Java 数据结构集合。包含了 Map、Queue、Lock、Semaphore、AtomicLong 等强大功能。

Jedis

直连

  1. 引入依赖

    1
    2
    3
    4
    5
    <dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>5.1.0</version>
    </dependency>
  2. 创建 Redis 对象,建立连接

    1
    2
    3
    4
    5
    6
    7
    private Jedis jedis;

    void setUp() {
    jedis = new Jedis("host", port);
    jedis.auth("password");
    jedis.select(0);
    }
  3. 使用 Redis,方法名与 Redis 命令一致

    1
    2
    3
    4
    5
    6
    void testString() {
    String result = jedis.set("animal", "dog");
    System.out.println("result = " + result);
    String name = jedis.get("animal");
    System.out.println("name = " + name);
    }
  4. 释放连接

    1
    2
    3
    4
    5
    void close() {
    if (jedis != null) {
    jedis.close();
    }
    }

连接池

Jedis 是线程不安全的,频繁地创建和销毁连接会影响性能,所以使用 Jedis 连接池代替直连方式。

  1. 连接池类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class JedisConnectionFactory {
    private static final JedisPool jedisPool;

    static {
    JedisPoolConfig poolConfig = new JedisPoolConfig();
    poolConfig.setMaxTotal(8);
    poolConfig.setMaxIdle(8);
    poolConfig.setMinIdle(0);
    jedisPool = new JedisPool(poolConfig,
    "host", port, timeout, "password");
    }

    public static Jedis getJedis() {
    return jedisPool.getResource();
    }
    }

  2. 创建 Redis 对象时,使用连接池

    1
    2
    3
    4
    5
    6
    7
    8
    private Jedis jedis;

    void setUp() {
    // jedis = new Jedis("host", port);
    // jedis.auth("password");
    jedis = JedisConnectionFactory.getJedis();
    jedis.select(0);
    }

SpringDataRedis

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

SpringDataRedis 提供了对 Lettuce 和 Jedis 的整合。

提供了 RedisTemplate 工具类,其中封装了对 Redis 的各种操作:

API 返回值类型 说明
redisTemplate.opsForValue() ValueOperations 操作 String 类型数据
redisTemplate.opsForHash() HashOperations 操作 Hash 类型数据
redisTemplate.opsForList() ListOperations 操作 List 类型数据
redisTemplate.opsForSet() SetOperations 操作 Set 类型数据
redisTemplate.opsForZSet() ZSetOperations 操作 SortedSet 类型数据
redisTemplate 通用的命令

使用

SpringBoot 提供了对 SpringDataRedis 的支持,创建 SpringBoot 项目即可。

  1. 引入依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!-- Redis 依赖 -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <!-- 连接池依赖 -->
    <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.12.0</version>
    </dependency>
  2. 配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    spring:
    data:
    redis:
    host:
    port:
    password:
    lettuce:
    pool:
    max-active: 8 # 最大连接数
    max-idle: 8 # 最大空闲连接
    min-idle: 0 # 最小空闲连接
    max-wait: 100 # 连接等待时间
  3. 注入 RedisTemplate

    1
    2
    @Autowired
    private RedisTemplate redisTemplate;
  4. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @SpringBootTest
    class Test {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Test
    void test() {
    redisTemplate.opsForValue().set("animal", "dog");
    Object animal = redisTemplate.opsForValue().get("animal");
    System.out.println("animal = " + animal);
    }
    }

RedisTemplate 序列化

方案一:

  1. 自定义 RedisTemplate

  2. 修改 RedisTemplate 的序列化器为 GenericJackson2JsonRedisSerializer

  • 优点:自动序列化和反序列化
  • 缺点:占用额外内存空间记录类的字节码

方案二:

  1. 使用 StringRedisTemplate
  2. 写入 Redis 时,手动把对象序列化为 JSON
  3. 读取 Redis 时,手动把读取到的 JSON 反序列化为对象
  • 优点:省去了自定义的过程,占用内存少
  • 缺点:编写麻烦,每次存取数据都需手动序列化和反序列化