Redis 基础
一、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 | cd /usr/local |
第三步:运行编译命令
1 | make && make install |
不报错即安装成功,默认安装路径为 /usr/local/bin
1 | [root@localhost01 bin]# pwd |
- redis-cli:命令行客户端
- redis-server:服务端启动脚本
- redis-sentinel:哨兵启动脚本
四、Redis 启动方式
启动方式:
- 默认启动
- 指定配置启动
- 开机自启
默认启动
默认为 前台启动
,会阻塞整个会话窗口。
1 | redis-server |
指定配置启动
修改 Redis 配置文件,Redis 根目录下的 redis.conf 文件:
1 | # 备份 |
其他常见配置:
1 | # 监听的端口 |
启动:
1 | cd /user/local/redis |
停止:
1 | redis-cli -a password shutdown |
开机自启
通过配置设置开机自启。
新建一个系统服务文件:
1 | vi /etc/systemd/system/redis.service |
内容如下:
1 | [Unit] |
重载系统服务:
1 | systemctl daemon-reload |
操作 Reids:
1 | systemctl start 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 | project:user:1 |
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
2
3
4
5<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.1.0</version>
</dependency>创建 Redis 对象,建立连接
1
2
3
4
5
6
7private Jedis jedis;
void setUp() {
jedis = new Jedis("host", port);
jedis.auth("password");
jedis.select(0);
}使用 Redis,方法名与 Redis 命令一致
1
2
3
4
5
6void testString() {
String result = jedis.set("animal", "dog");
System.out.println("result = " + result);
String name = jedis.get("animal");
System.out.println("name = " + name);
}释放连接
1
2
3
4
5void close() {
if (jedis != null) {
jedis.close();
}
}
连接池
Jedis 是线程不安全的,频繁地创建和销毁连接会影响性能,所以使用 Jedis 连接池代替直连方式。
连接池类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public 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();
}
}创建 Redis 对象时,使用连接池
1
2
3
4
5
6
7
8private 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
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>配置文件
1
2
3
4
5
6
7
8
9
10
11
12spring:
data:
redis:
host:
port:
password:
lettuce:
pool:
max-active: 8 # 最大连接数
max-idle: 8 # 最大空闲连接
min-idle: 0 # 最小空闲连接
max-wait: 100 # 连接等待时间注入 RedisTemplate
1
2
private RedisTemplate redisTemplate;测试
1
2
3
4
5
6
7
8
9
10
11
12
class Test {
private RedisTemplate<String, String> redisTemplate;
void test() {
redisTemplate.opsForValue().set("animal", "dog");
Object animal = redisTemplate.opsForValue().get("animal");
System.out.println("animal = " + animal);
}
}
RedisTemplate 序列化
方案一:
自定义 RedisTemplate
修改 RedisTemplate 的序列化器为 GenericJackson2JsonRedisSerializer
- 优点:自动序列化和反序列化
- 缺点:占用额外内存空间记录类的字节码
方案二:
- 使用 StringRedisTemplate
- 写入 Redis 时,手动把对象序列化为 JSON
- 读取 Redis 时,手动把读取到的 JSON 反序列化为对象
- 优点:省去了自定义的过程,占用内存少
- 缺点:编写麻烦,每次存取数据都需手动序列化和反序列化