Redis 中的发布订阅和事务

Posted by 彭楷淳 on 2021-01-26
Estimated Reading Time 4 Minutes
Words 1.2k In Total
Viewed Times

发布订阅


Redis 的发布订阅系统有点类似于我们生活中的电台,电台可以在某一个频率上发送广播,而我们可以接收任何一个频率的广播。订阅消息的方式如下:

1
2
3
4
5
6
7
8
9
10
11
127.0.0.1:6379> subscribe c1 c2 c3
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "c1"
3) (integer) 1
1) "subscribe"
2) "c2"
3) (integer) 2
1) "subscribe"
2) "c3"
3) (integer) 3

这个表示接收 c1,c2,c3 三个频道传来的消息,发送消息的方式如下:

1
2
127.0.0.1:6379> publish c1 "hello redis!"
(integer) 1

当 c1 这个频道上有消息发出时,此时在消息订阅控制台可以看到如下输出:

1
2
3
1) "message"
2) "c1"
3) "hello redis!"

在 rediR 中,我们也可以使用模式匹配订阅,如下:

1
2
3
4
5
127.0.0.1:6379> psubscribe c*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "c*"
3) (integer) 1

此时可以接收到所有以 c 开头的频道发来的消息。

tips

Redis 中的发布订阅系统在某些场景下还是非常好用的,但是也有一些问题需要注意:由于网络在传输过程中可能会遭遇断线等意外情况,断线后需要进行重连,然而这会导致断线期间的数据丢失。

事务


既然 Redis 是一种 NoSQL 数据库,那它当然也有事务的功能,不过这里的事务和我们关系型数据库中的事务有一点点差异。Redis 中事务的用法非常简单,我们通过 multi 命令开启一个事务,如下:

1
2
127.0.0.1:6379> multi
OK

在 multi 命令执行之后,我们可以继续发送命令去执行,此时的命令不会被立马执行,而是放在一个队列中,如下:

1
2
3
4
5
6
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED

当所有的命令都输入完成后,我们可以通过 exec 命令发起执行,也可以通过 discard 命令清空队列,如下:

1
2
3
4
127.0.0.1:6379> exec
1) OK
2) OK
3) OK

事务中的异常情况

Redis 中事务的异常情况总的来说分为两类:

  1. 进入队列之前就能发现的错误,比如命令输错;
  2. 执行 exec 之后才能发现的错误,比如给一个非数字字符加 1 ;

那么对于这两种不同的异常,Redis 中有不同的处理策略。对于第一种错误,服务器会对命令入队失败的情况进行记录,并在客户端调用 exec 命令时,拒绝执行并自动放弃这个事务(这个是2.6.5之后的版本做法,之前的版本做法小伙伴可以参考官方文档)。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set kv1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3 3 3
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) (error) ERR syntax error
4) OK
127.0.0.1:6379> keys *
1) "k4"
2) "k2"
3) "kv1"

而对于第二种情况,Redis 并没有对它们进行特别处理, 即使事务中有某个/某些命令在执行时产生了错误, 事务中的其他命令仍然会继续执行。如下:

1
2
3
4
5
6
7
8
9
10
11
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 vv
QUEUED
127.0.0.1:6379> INCR k1
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (error) ERR value is not an integer or out of range
127.0.0.1:6379> GET k1
"vv"

不同于关系型数据库,Redis 中的事务出错时没有回滚,对此,官方的解释如下:

Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。

watch 命令

事务中的 watch 命令可以用来监控一个 key,通过这种监控,我们可以为 Redis 事务提供(CAS)行为。 如果有至少一个被 watch 监视的键在 exec 执行之前被修改了,那么整个事务都会被取消,exec 返回 nil-reply 来表示事务已经失败。通过 unwatch 命令,可以取消对一个 key 的监控。

发布订阅和事务我们就介绍这么多,更多命令小伙伴们可以参考官方文档

更多干货请移步:https://antoniopeng.com


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !