一、事务与批量操作

1.1 简介

Redis 事务的特性

  • redis的事务只是保证了多条命令的串行执行

  • 并不能保证执行命令的原子性

  • redis事务只有在入队异常的时候会回滚,进入server执行并不会回滚

1.2 常用命令

显式开启Redis事务命令 MULTI

MULTI

EXEC提交事务,执行队列命令

EXEC

DISCARD 清除事务中的commands队列,并恢复连接状态;

DISCARD

watch 给事务一个执行条件

WATCH

清除事务的执行条件

UNWATCH

补充说明:

  • MULTI 开启后,后续命令先入队,直到 EXEC 才真正执行。

  • Redis 事务保证的是“队列中的命令串行执行”,不是关系型数据库那种失败即回滚的强事务。

  • WATCH 的作用更接近乐观锁:当被监视的 key 在 EXEC 前发生变化时,事务会放弃执行。

转账示例

local:1>set a 100
"OK"
local:1>set b 100
"OK"
local:1>multi
"OK"
local:1>incrby a 10
"QUEUED"
local:1>decrby b 10
"QUEUED"
local:1>exec
1) "OK"
2) "110"
3) "OK"
4) "90"

事务失败示例,事务不能保证原子性

local:1>set t1 t1
"OK"
local:1>set t2 10
"OK"
local:1>multi
"OK"
local:1>incrby t1 1
"QUEUED"
local:1>incrby t2 1
"QUEUED"
local:1>exec
1) "OK"
1) "ERR value is not an integer or out of range"
1) "OK"
1) "11"
1) "OK"
local:1>get t1
"t1"
local:1>get t2
"11"

带watch 监控的事务

local:1>watch t1 # 监控t1
"OK"
local:1>set t1 10 # 改变t1
"OK"
local:1>multi
"OK"
local:1>set t2 10
"QUEUED"
local:1>exec
local:1>get t2
"11"
local:1>get t1
"10"

补充说明:

  • 在事务开启后,客户端通常会进入 (TX) 状态,表示后续命令只是入队,还没有真正执行。

  • 如果 WATCH 监控的 key 在 EXEC 前被修改,EXEC 会返回 (nil),表示整个事务队列被放弃执行。

  • 这里更准确地说是“事务未执行”,而不是像关系型数据库那样“执行后回滚”。

视频补充:事务实践中的两个重点

  • 如果命令在入队阶段就有语法问题,事务会直接失败;但如果是执行阶段出现类型错误,其他命令仍可能继续执行,不会整体回滚。

  • WATCH + MULTI + EXEC 常用来实现带条件的更新,例如扣减库存、账户转账等场景中的并发控制。

二、订阅与发布

2.1 简介

什么是发布订阅?

Redis支持发布-订阅(Pub/Sub )模式,它允许消息的发布者将消息发送给订阅者,实现了一对多的消息 传递机制。Redis订阅与发布的参与者有以下三个:

  • 发布者(Publisher):发布者是发送消息的一方。它使用 PUBLISH 命令将消息发送到指定的频道 (Channel)。一个发布者可以向多个频道发布消息。

  • 频道(Channel):频道是消息的目标地址。订阅者通过订阅指定的频道来接收发布者发送的消息。 频道由字符串表示,可以使用任意字符串作为频道名。

  • 订阅者(Subscriber):订阅者是接收消息的一方。它使用 SUBSCRIBE命令来订阅一个或多个频道, 然后等待接收发布者发送的消息。一个订阅者可以同时订阅多个频道。

2.2 常用命令

订阅,我们打开一个客户端先订阅一个频道channel1

local:1>subscribe channel1
Switch to Pub/Sub mode.
Close console tab to stop listen for messages.
1) "subscribe"
1) "channel1"
1) "1"

我们再起一个客户端,给频道channel1发送消息hi

local:1>publish channel1 hi
"1"

我们看第一个客户端发现多了以下消息

1) "message"
1) "channel1"
1) "hi"

2.3 实现

视频补充:Pub/Sub 内部实现思路

  • Redis 会把频道维护在哈希表 server.pubsub_channels 中,key 是频道名,value 是订阅该频道的客户端链表。

  • 当客户端执行 SUBSCRIBE 时,Redis 会先查找频道是否存在:

  • 如果频道已存在,就把当前客户端挂到该频道对应的订阅链表中。
  • 如果频道不存在,就先创建频道,再把客户端加进去。

  • 当发布者执行 PUBLISH 时,Redis 会根据频道名找到对应链表,并一次性遍历所有订阅者进行消息投递。

  • 这也意味着 Pub/Sub 更偏向实时广播,消息默认不做持久化,也不保证离线重投;如果业务需要可追溯和可靠消费,通常要结合 Stream 或专业 MQ 来做。