redis 的 pipeline 和 multi 命令都和批量执行有关, 而它们面对的场景和解决的问题又各部相同, 容易使初识者混淆;
本文即总结一下这两个小众的 redis 命令;
pipeline
pipepline 是一种将多个命令打包在一起一次性发送到 redis server 的方法, 适用于那些不需要事务性的操作, 这样可以减少网络延迟, 从而提高性能;
multi
multi 是 redis 中实现事务处理的机制, 即 multi 中的命令只在事务提交时执行, 从而确保其所包含的所有命令在执行过程中不被其他命令打断;1
2
3
4
5
6
7
8
9
10127.0.0.1:6379> GET name // name = xxx
"xxx"
127.0.0.1:6379> MULTI // 开启事务
OK
127.0.0.1:6379> SET name yyy // 事务中命令: 设置 name = yyy
QUEUED
127.0.0.1:6379> DISCARD // 取消事务
OK
127.0.0.1:6379> GET name // 事务中的命令未执行
"xxx"
redis 为了提升性能而对 multi 采用了一种简单的事务保障机制:
- 命令的语法错误在命令入队前就检测, 检测报错立即中断事务, 之前提交的事务都不会生效;
- 命令在执行时才能检测出的错误 (如数据类型错误), multi 命令不会回滚事务, 除了报错的命令之外, 其余命令都会被实际执行;
multi + watch
redis multi 命令虽然实现了事务, 但是有很多场景我们需要在指定条件下才执行事务, multi 命令无法依据条件判断是否执行命令, 为此 redis 提供了 watch 命令, 其实现了一种乐观锁机制, 其允许监听指定的 key, 当其对应的 value 在事务 exec 执行之前被修改了, 事务将被中断;
因此基于 multi + watch 命令可以实现一种基于有限条件的事务 —— 当指定 key 不被其他线程修改时, 执行事务:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import redis
r = redis.Redis(host='localhost', port=6379, db=0)
# 开始监视键
r.watch('key')
# 开启事务
multi_ctx = r.multi()
try:
# 事务中的命令
multi_ctx.decr('key')
multi_ctx.decr('key')
# 执行事务
r.exec()
except redis.WatchError:
print('事务被中断')