Redis
1. Redis概述
1.1 NoSQL概述
关系型数据库特点:
- 灵活强大的SQL语句;
- 清晰的数据关系;
- 安全的事务处理。
然而随着数据量的不断增大,传统关系型数据库逐渐暴露出一些问题:
- 数据间的关系维护消耗大量系统资源;
- 复杂的关系维护导致操作效率很低,甚至宕机;
- 对数据库的维护几乎不可能实现。
为了处理海量数据,需要将关系型数据库中的关系去掉,因此诞生了NoSQL(not only sql)。
NoSQL拥有了处理大数据的能力,也损失了SQL的一些优点:
- NoSQL的数据间没有关系,数据可读性很差;
- 依然保留了事务处理,不过能力较SQL差了很多,不能保证数据的安全性、完整性。
NoSQL仅仅是一个概念,NoSQL数据库根据数据的存储模型和特点分为很多种类。
1.2 Redis是什么
2008年,意大利的一家创业公司Merzia推出了一款基于MySql的网站实时统计系统LLOOGG。
然而没过多久该公司的创始人Salvatore Sanfilippo便对MySQL的性能感到失望,于是他决定亲自为LLOOGG量身定做一个数据库,并于2009年开发完成,这个数据库就是Redis。
不过Salvatore Sanfilippo并不满足只将Redis用于LLOOGG这一款产品,而是希望更多的人使用它,于是在同一年Salvatore Sanfilippo将Redis开源发布并亲自维护至2020年7月。
Redis的使用场景:
- 作为关系型数据库的缓存存在,缓解数据库的压力;
- 大数据的运算处理;
- 大数据的排行。
2. Redis的安装
2.1 Linux安装Redis
-
下载Redis压缩包 -
解压(包中的内容是安装程序,而不是Redis应用程序) -
进入解压得到的安装目录,将文件夹下面的C代码进行编译 make
-
安装到指定的目录 make PREFIX=/usr/local/redis install
-
将安装目录下的redis.conf 配置文件复制到/usr/local/redis cp redis.conf /usr/local/redis
-
启动 执行/usr/local/redis/bin 下的redis-server ,启动服务端 /usr/local/redis/bin/redis-server
或 /usr/local/redis/bin/redis-server &
& :Linux全局可用,强制后台运行
-
配置 -
关闭
- 可通过杀死线程来关闭redis,不过不安全
- 执行
/usr/local/redis/bin/redis-cli shutdown
2.2 Windows安装Redis
- 下载
- 安装
3. Redis的数据类型
Redis中保存数据是以键值对的形式保存数据,没有表的形式:
? key --> value
其中:
-
key:全部都是字符串 -
value:有5种数据类型:
4. Redis命令
4.1 string
字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这便意味着该类型存入和获取的数据相同。
在Redis中,字符串类型的value最多可容纳的数据长度为512M。
-
set key value 赋值,如果key已存在,则会覆盖原有value -
get key 取值,如果key不存在,则返回nil,如果key对应的value不是字符串类型,则报错 -
del key 删除,返回值代表成功删除的条数 -
getset key value 先获取该key的值,然后再修改该key的值 -
incr key /decr key 使key对应的value自增或自减1,若key不存在,则新建该数据,初始value为0。若对应value不是数字类型,则报错 -
incrby key increment /decrby key increment 指定增量 -
append key value 拼接字符串。如果key存在,会在原有的value后面追加值;如果key不存在,则新建该数据
4.2 hash
Redis中的hash类型可以看做是具有String key和String value的map容器,所以该类型非常适合存储值和对象的信息。
-
hset key field value 为指定的key设置value(单个键值对) -
hmset key field1 value1 field2 value2 ... 为指定的key设置value(多个键值对) -
hget key field 获取指定key中的指定filed的值 -
hmget key field1 field2 ... 获取指定key中的多个filed的值 -
hgetall key 获取指定key中所有filed的键和值 -
hdel key field1 field2 ... 删除指定key中指定的field,若删除后hash为空,则该条数据自动删除 -
del key 同样可以删除hash类型的数据
4.3 list
Redis中的list是链表,与数组结构相比,链表具有数据随机增删快的特点,适合数据变化频率高的场景。
使用list结构,我们可以轻松地实现最新消息排行等功能。
list的另一个应用就是消息队列,可以利用list的PUSH操作,将任务存在list中,然后工作线程再用POP操作将任务取出进行执行。
4.4 set
set对外提供的功能与list类似,是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择。
并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。
set集合的概念就是一堆不重复值的组合。利用Redis提供的set数据结构,可以存储一些集合性的数据。
比如在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。
Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能。
对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。
-
sadd
-
语法:SADD KEY_NAME VALUE1..VALUEN -
说明:Sadd 命令将一个或多个成员元素加入到集合中,已经存在于集合的成员元素将被忽略。 ? 假如集合 key 不存在,则创建一个只包含添加的元素作成员的集合。 -
返回值:被添加到集合中的新元素的数量,不包括被忽略的元素。 -
smembers
-
scard
-
语法:SCARD KEY_NAME -
说明:Scard 命令返回集合中元素的数量。 -
返回值:集合的数量。 ? 当集合 key 不存在时,返回 0 。 -
sismember
-
srem
- 语法:
SREM KEY MEMBER1..MEMBERN - 说明:Srem 命令用于移除集合中的一个或多个成员元素,不存在的成员元素会被忽略。
- 返回值:被成功移除的元素的数量,不包括被忽略的元素。
-
sdiff
- 语法:
SDIFF FIRST_KEY OTHER_KEY1..OTHER_KEYN - 说明:Sdiff 命令返回给定集合之间的差集。
- 返回值:包含差集成员的列表。
-
sdiffstore
-
sinter
- 语法:
SINTER KEY KEY1..KEYN - 说明:Sinter 命令返回给定所有给定集合的交集。
-
返回值:交集成员的列表。 -
sinterstore
-
sunion
- 语法:
SUNION KEY KEY1..KEYN - 说明:Sunion 命令返回给定集合的并集。
- 返回值:并集成员的列表。
-
sunionstore
-
语法:SUNIONSTORE DESTINATION KEY KEY1..KEYN -
说明:Sunionstore 命令将给定集合的并集存储在指定的集合 destination 中。 ? 如果 destination 已经存在,则将其覆盖。 -
返回值:结果集中的元素数量。
4.5 sorted set
sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。
当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构。
另外还可以用Sorted Sets来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务,让重要的任务优先执行。
-
zadd
-
语法:ZADD KEY_NAME SCORE1 VALUE1.. SCOREN VALUEN -
说明:Zadd 命令用于将一个或多个成员元素及其分数值加入到有序集当中。 ? 如果某个成员已经是有序集的成员,那么更新这个成员的分数值,并通过重新插入这个成员元素,来保证该成员在正确的位置上。 ? 分数值可以是整数值或双精度浮点数。 ? 如果有序集合 key 不存在,则创建一个空的有序集并执行 ZADD 操作。 -
返回值:被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。 -
zscore
- 语法:
ZSCORE key member - 说明:Zscore 命令返回有序集中,成员的分数值。
- 返回值:成员的分数值,以字符串形式表示。
-
zrange
-
语法:ZRANGE key start stop [WITHSCORES] -
说明:Zrange 返回有序集中,指定区间内的成员。 ? 其中成员的位置按分数值递增(从小到大)来排序。 ? 具有相同分数值的成员按字典序(lexicographical order )来排列。 ? 如果你需要成员按值递减(从大到小)来排列,请使用 ZREVRANGE 命令。 ? 下标参数 start 和 stop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。 ? 你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。 -
返回值:指定区间内,带有分数值(可选)的有序集成员的列表。 -
zrevrange
-
语法:ZREVRANGE key start stop [WITHSCORES] -
说明:Zrevrange 命令返回有序集中,指定区间内的成员。 ? 其中成员的位置按分数值递减(从大到小)来排列。 ? 具有相同分数值的成员按字典序的逆序(reverse lexicographical order)排列。 ? 除了成员按分数值递减的次序排列这一点外, ZREVRANGE 命令的其他方面和 ZRANGE 命令一样。 -
返回值:指定区间内,带有分数值(可选)的有序集成员的列表。 -
zrank
-
语法:ZRANK key member -
说明:Zrank 返回有序集中指定成员的排名。 ? 其中有序集成员按分数值递增(从小到大)顺序排列。 -
返回值:如果成员是有序集 key 的成员,返回 member 的排名。 ? 如果成员不是有序集 key 的成员,返回 nil 。 -
zrevrank
-
语法:ZREVRANK key member -
说明:Zrevrank 命令返回有序集中成员的排名。 ? 其中有序集成员按分数值递减(从大到小)排序。 ? 排名以 0 为底,也就是说, 分数值最大的成员排名为 0 。 ? 使用 ZRANK 命令可以获得成员按分数值递增(从小到大)排列的排名。 -
返回值:如果成员是有序集 key 的成员,返回成员的排名。 ? 如果成员不是有序集 key 的成员,返回 nil 。 -
zincrby
-
语法:ZINCRBY key increment member -
说明:Zincrby 命令对有序集合中指定成员的分数加上增量 increment ? 可以通过传递一个负数值 increment ,让分数减去相应的值,比如 ZINCRBY key -5 member ,就是让 member 的 score 值减去 5 。 ? 当 key 不存在,或分数不是 key 的成员时, ZINCRBY key increment member 等同于 ZADD key increment member 。 -
返回值:member 成员的新分数值,以字符串形式表示。
4.6 其他
-
keys
- 语法:
KEYS PATTERN - 说明:Keys 命令用于查找所有符合给定模式 pattern 的 key 。
- 返回值:符合给定模式的 key 列表 (Array)。
-
rename
- 语法:
RENAME OLD_KEY_NAME NEW_KEY_NAME - 说明:Rename 命令用于修改 key 的名称 。
- 返回值:改名成功时提示 OK ,失败时候返回一个错误。
当 OLD_KEY_NAME 和 NEW_KEY_NAME 相同,或者 OLD_KEY_NAME 不存在时,返回一个错误。 当 NEW_KEY_NAME 已经存在时, RENAME 命令将覆盖旧值。 -
exists
- 语法:
EXISTS KEY_NAME - 说明:EXISTS 命令用于检查给定 key 是否存在。
- 返回值:若 key 存在返回 1 ,否则返回 0 。
-
del
- 语法:
DEL KEY_NAME - 说明:DEL 命令用于删除已存在的键。
- 返回值:被删除 key 的数量。
-
type
-
expire
-
语法:EXPIRE KEY_NAME TIME_IN_SECONDS -
说明:Expire 命令用于设置 key 的过期时间。 ? key 过期后将不再可用。 -
返回值:设置成功返回 1 。 ? 当 key 不存在或者不能为 key 设置过期时间时返回 0 。 -
pexpire
- 语法:
PEXPIRE KEY_NAME TIME_IN_MILLISECONDS - 说明:Pexpire 命令用于设置 key 的过期时间,以毫秒计。
key 过期后将不再可用。 - 返回值:设置成功返回 1 。
当 key 不存在或者不能为 key 设置过期时间时返回 0 。 -
persist
-
ttl
-
语法:TTL KEY_NAME -
说明:TTL 命令以秒为单位返回 key 的剩余过期时间。 -
返回值:当 key 不存在时,返回 -2 。 ? 当 key 存在但没有设置剩余生存时间时,返回 -1 。 ? 否则,以秒为单位,返回 key 的剩余生存时间。 -
pttl
-
语法:PTTL KEY_NAME -
说明:Pttl 命令以毫秒为单位返回 key 的剩余过期时间。 -
返回值:当 key 不存在时,返回 -2 。 ? 当 key 存在但没有设置剩余生存时间时,返回 -1 。 ? 否则,以毫秒为单位,返回 key 的剩余生存时间。
5. 客户端的使用
5.1 Redis客户端
Redis不仅是使用命令来操作,现在基本上主流的语言都有客户端支持,比如Java、C、C++、C#、PHP等。
在官网列有一些Java的客户端,有Jedis、Redisson、Jredis、JDBC-Redis等,其中官方推荐使用的Jedis和Reddisson。
目前使用最普遍的就是Jedis。
5.2 Jedis的基本使用
-
导入依赖 -
测试代码 Jedis jedis = new Jedis("xxx.xxx.xxx.xxx", 6379);
String rs = jedis.set("username", "zhangsan");
System.out.println(rs);
5.3 Jedis连接池
Jedis拥有连接池来管理Jedis对象。
JedisPoolConfig config = new JedisPoolConfig();
JedisPool jedisPool = new JedisPool(config, "xxx.xxx.xxx.xxx", 6379, 10000, "your_password");
Jedis jedis = jedisPool.getResource();
String username = jedis.get("username");
System.out.println(username);
jedis.close();
可以自行抽取JedisUtils,也可以整合进Spring
6. 消息发布与订阅
6.1 pub/sub模式
发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:
当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:
6.2 发布/订阅命令
-
subscribe
- 语法:
SUBSCRIBE channel [channel ...] - 说明:Subscribe 命令用于订阅给定的一个或多个频道的信息。
- 返回值:接收到的信息。
-
publish
- 语法:
PUBLISH channel message - 说明:Publish 命令用于将信息发送到指定的频道。
-
返回值:接收到信息的订阅者数量。 -
psubscribe
-
语法:PSUBSCRIBE pattern [pattern ...] -
说明:Psubscribe 命令订阅一个或多个符合给定模式的频道。 ? 每个模式以 * 作为匹配符,比如 it* 匹配所有以 it 开头的频道( it.news 、 it.blog 、 it.tweets 等等)。 ? news.* 匹配所有以 news. 开头的频道( news.it 、 news.global.today 等等),诸如此类。 -
返回值:接收到的信息。
7. 多数据库
Redis也是有多个数据库的,默认拥有16个数据库,每个数据库是由一个整数索引标识(0~15),而不是由一个数据库名称。
默认情况下,一个客户端连接到数据库0。
数据库的数量是可以配置的,修改redis.conf下的databases参数。
每个数据库都有属于自己的空间,不必担心之间的key冲突。
-
select
- 语法:
SELECT index - 说明:Select 命令用于切换到指定的数据库,数据库索引号 index 用数字值指定,以 0 作为起始索引值。
- 返回值:总是返回 OK 。
-
flushdb
- 语法:
FLUSHDB - 说明:Flushdb 命令用于清空当前数据库中的所有 key。
- 返回值:总是返回 OK 。
-
flushall
- 语法:
FLUSHALL - 说明:Flushall 命令用于清空整个 Redis 服务器的数据(删除所有数据库的所有 key )。
- 返回值:总是返回 OK 。
-
move
- 语法:
MOVE KEY_NAME DESTINATION_DATABASE - 说明:MOVE 命令用于将当前数据库的 key 移动到给定的数据库 db 当中。
- 返回值:移动成功返回 1 ,失败则返回 0 。
8. Redis事务
Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证:
- 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
一个事务从开始到执行会经历以下三个阶段:
不过Redis的事务并不能保证安全,如果在事务过程中出现错误,事务会继续执行,而不会自动回滚。
-
multi
-
exec
-
discard
- 语法:
DISCARD - 说明:Discard 命令用于取消事务,放弃执行事务块内的所有命令。
- 返回值:总是返回 OK 。
9. Redis持久化
9.1 数据持久化
关系型数据库 MySQL:
- 任何的增删改语句,都是在硬盘上做的操作;
- 关闭服务,或断电以后,数据依然存在。
非关系型数据库 Redis:
- 所有的增删改,都是在内存上做的操作;
- 关闭服务,或断电以后,数据丢失。
不过我们依然可以获取到曾经存过的数据,这说明Redis是有持久化的。
Redis的持久化有两种策略:RDB、AOF
9.2 RDB
RDB是Redis的默认持久化机制,它相当于快照,保存的是一种状态。
持久化文件保存在redis的安装目录下(/)——dump.rdb
调用RDB持久化数据的方式有:
- 正常关闭Redis时;
- 执行save或bgsave命令时;
- 在一定时间内,有大量的key发生变化时。
优点:
缺点:
9.3 AOF
AOF是AppendOnly File的缩写,是Redis系统提供了一种记录Redis操作的持久化方案。
在AOF生成的文件中,将忠实记录发生在Redis的操作,从而达到在Redis服务器重启或者当机之后,继续恢复之前数据状态的机制。
开启AOF作为持久化机制:
- 修改redis配置文件中的appendonly参数为yes
优点:
缺点:
|