【Redis】redis事务和发布订阅

Redis 事务

Redis 事务可以一次执行多个命令, 并且带有以下三个重要的特性:

  • 批量操作在发送 EXEC 命令前被放入队列缓存。
  • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

一个事务从开始到执行会经历以下三个阶段:

  • 开始事务。
  • 命令入队。
  • 执行事务。

示例

以下是一个事务的例子, 它先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令:

bash 复制代码
127.0.0.1:6379(TX)> set name redis
QUEUED
127.0.0.1:6379(TX)> get name
QUEUED
127.0.0.1:6379(TX)> SADD tag "redis in actions"
QUEUED
127.0.0.1:6379(TX)> SMEMBERS tag
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) "redis"
3) (integer) 1
4) 1) "redis in actions"
127.0.0.1:6379> 

需要注意的是,单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。(TX 是transaction的意思)

事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。这与MySQL中的事务是有所差别的。 示例如下:

bash 复制代码
127.0.0.1:6379(TX)> set a aaa
QUEUED
127.0.0.1:6379(TX)> set b bbb 
QUEUED
127.0.0.1:6379(TX)> set c ccc
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
3) OK

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> DISCARD
OK
127.0.0.1:6379> exec
(error) ERR EXEC without MULTI
127.0.0.1:6379> 

如果在 set b bbb 处失败,set a 已成功不会回滚,set c 还会继续执行。同时注意discard是放弃事务的意思。

Redis 事务命令

下表列出了 redis 事务的相关命令:

命令 说明
DISCARD 取消事务,放弃执行事务块内的所有命令。
EXEC 执行所有事务块内的命令。
MULTI 标记一个事务块的开始。
UNWATCH 取消 WATCH 命令对所有 key 的监视。
WATCH key [key ...] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

Redis 发布订阅

Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (publisher) 发送消息,订阅者 (ssubscriber) 接收消息。Redis 客户端可以订阅任意数量的频道(channel)。

redis发布订阅的通信模型有如下特点:

  • RedisServer中可以创建多个channel
  • 一个订阅者可以订阅多个channel
  • 当发布者向一个频道中发布一条消息时,所有的订阅者都将会收到消息
  • Redis的发布订阅模型没有消息积压功能,即新加入的订阅者收不到发布者之前发布的消息
  • 当订阅者收到消息时,消息内容如下:
    • 第一行:固定内容message
    • 第二行:channel的名称
    • 第三行:收到的新消息

下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 ------ client2 、 client5 和 client1 之间的关系:

当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

示例

以下例子演示了发布订阅是如何工作的,需要开启两个 redis-cli 客户端。在这个例子中我们创建了订阅频道名为 goodschat:

第一个 redis-cli 客户端

bash 复制代码
127.0.0.1:6379> SUBSCRIBE goodschat
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "goodschat"
3) (integer) 1

现在,我们先重新开启个 redis 客户端,然后在同一个频道 goodschat 发布两次消息,回过头去看订阅者就能接收到消息。

第二个 redis-cli 客户端

bash 复制代码
127.0.0.1:6379> PUBLISH goodschat "hello ,welcome to learn redis"
(integer) 1
127.0.0.1:6379> PUBLISH goodschat "you have to study hard"
(integer) 1
127.0.0.1:6379> 

订阅者的客户端会显示如下消息

bash 复制代码
1) "message"
2) "goodschat"
3) "hello ,welcome to learn redis"
1) "message"
2) "goodschat"
3) "you have to study hard"

Redis 发布订阅命令

下表列出了 redis 发布订阅常用命令:

命令 说明
PSUBSCRIBE pattern [pattern ...] 订阅一个或多个符合给定模式的频道。
PUBSUB subcommand [argument [argument ...]] 查看订阅与发布系统状态。
PUBLISH channel message 将信息发送到指定的频道。
PUNSUBSCRIBE [pattern [pattern ...]] 退订所有给定模式的频道。
SUBSCRIBE channel [channel ...] 订阅给定的一个或多个频道的信息。
UNSUBSCRIBE [channel [channel ...]] 指退订给定的频道。

消息队列和发布订阅区别

发布订阅模式 是将消息通知每一个订阅者,正常情况下回收到完全相同的消息。而消息队列是消息发布者发表消息后只有其中一个消息订阅者能收到消息,订阅者争抢接受消息,实现的是一个抢的功能。

更多关于redis的知识分享,请前往博客主页。编写过程中,难免出现差错,敬请指出

相关推荐
魔道不误砍柴功2 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2342 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨2 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
测开小菜鸟4 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
Ai 编码助手4 小时前
MySQL中distinct与group by之间的性能进行比较
数据库·mysql
P.H. Infinity4 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天5 小时前
java的threadlocal为何内存泄漏
java
陈燚_重生之又为程序员5 小时前
基于梧桐数据库的实时数据分析解决方案
数据库·数据挖掘·数据分析
caridle5 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
白云如幻5 小时前
MySQL排序查询
数据库·mysql