Redis 笔记(08)— 事务(一次执行多条命令、命令 watch/multi/exec/discard、错误处理)
1. 事务概念
Redis
中的事务 (transaction
)是一组命令的集合。事务同命令一样是 Redis
的最小执行单位,一个事务中的命令要么都执行,要么都不执行。事务的原理是先将属于一个事务的命令发送给 Redis
,然后再让 Redis
依次执行这些命令。
2. 事务命令
命令 | 说明 |
---|---|
watch key[key…] | 锁定key,直到执行了multi/exec命令 |
multi | 标记一个事务块开始 |
exec | 执行所有multi之后发的命令 |
discard | 丢弃所有multi之后发的命令 |
3. 事务使用
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a 1
QUEUED
127.0.0.1:6379> set b 2
QUEUED
127.0.0.1:6379> set c 3
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) OK
127.0.0.1:6379>
multi
标记一个事务的开始,表示之后发送的命令都属于同一个事务,而 exec
命令则告诉 Redis
将等待执行的事务队列中的所有命令(即刚才返回 QUEUED
的命令)按照发送顺序依次执行。exec
命令的返回值是事务命令的返回值组成的列表,返回值顺序和命令的顺序相同。
Redis
会保证一个事务中的命令要么都执行,要么都不执行。 如果在执行 exec
命令之前客户端断线了那么 Redis
会自动清空事务队列,事务中的所有命令都不会执行;而如果客户端执行了 exec
命令后断线也没有关系,Redis
已经记录了所有要执行的命令。
所有的指令在 exec
之前不执行,而是缓存在服务器的一个事务队列中,服务器一旦收到 exec
指令,才开执行整个事务队列,执行完毕后一次性返回所有指令的运行结果。因为 Redis
的单线程特性,它不用担心自己在执行队列的时候被其它指令打搅,可以保证他们能得到的「原子性」执行。
Redis
为事务提供了一个 discard
指令,用于丢弃事务缓存队列中的所有指令,在 exec
执行之前。
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set x 1
QUEUED
127.0.0.1:6379(TX)> set y 2
QUEUED
127.0.0.1:6379(TX)> set z 3
QUEUED
127.0.0.1:6379(TX)> discard # 丢弃 multi 之后发送的命令
OK
127.0.0.1:6379> get x
(nil)
127.0.0.1:6379> mget x y z
1) (nil)
2) (nil)
3) (nil)
127.0.0.1:6379>
4. 错误处理
如果 Redis
事务中一个命令发生错误,那么其它的命令还会执行吗?我们主要看两种错误:
语法错误
只要事务中有一个命令的语法发生错误,那么整个事务中的命令都不会执行。
运行错误
运行错误是指在执行命令时出现的错误,这种错误在实际执行之前是无法发现的,当事务中出现这种运行错误时,其它命令仍然会继续执行的。
> multi
OK
> set books python
QUEUED
> incr books
QUEUED
> set phone huawei
QUEUED
> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
> get books
"python"
> get phone
"huawei"
上面的例子是事务执行到中间遇到失败了,因为我们不能对一个字符串进行数学运算,事务在遇到指令执行失败后,后面的指令还继续执行,所以 phone 的值能继续得到设置。
到这里,你应该明白 Redis
的事务根本不能算「原子性」,而仅仅是满足了事务的「隔离性」,隔离性中的串行化——当前执行的事务有着不被其它事务打断的权利。
Redis
事务不支持关系型数据库事务提供的回滚功能。
5. watch 命令
watch
命令可以监控一个或者多个键,一旦其中有一个键被修改或删除,之后的事务就不会执行。监控一直持续到 exec
命令 (事务中的命令是在 exec
命令之后执行的,所以在 multi
命令之后可以修改 watch
监控的键值)。
watch
会在事务开始之前盯住 1 个或多个关键变量,当事务执行时,也就是服务器收到了 exec
指令要顺序执行缓存的事务队列时,Redis
会检查关键变量自 watch
之后,是否被修改了 (包括当前事务所在的客户端)。如果关键变量被人动过了,exec
指令就会返回 null
回复告知客户端事务执行失败,这个时候客户端一般会选择重试。
127.0.0.1:6379> set a 1
OK
127.0.0.1:6379> watch a # 监控 a 是否变化
OK
127.0.0.1:6379> set a 2 # 键被修改,则后面的 multi 不会被执行
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a 3
QUEUED
127.0.0.1:6379> exec # 变量被修改,服务器回复 nil
(nil)
127.0.0.1:6379> get a # 被修改之后的值,multi 命令之后的值没有被执行
"2"
127.0.0.1:6379>
也可以用 unwatch
命令来取消监控。
Redis
事务在执行时是单线程运行的。但是在执行前有可能别的客户端已经修改了事务里执行的 key
。所以在 multi
事务开始之前用 watch
检测这个 key
避免被其他客户端改变的。如果这个 key
被改变 了 exec
的时候就会报错不执行这个事务。
Redis
禁止在 multi
和 exec
之间执行 watch
指令,而必须在 multi
之前做好盯住关键变量,否则会出错。
6. 事务结合管道使用
Redis
事务在发送每个指令到事务缓存队列时都要经过一次网络读写,当一个事务内部的指令较多时,需要的网络 IO
时间也会线性增长。所以通常 Redis
的客户端在执行事务时都会结合 pipeline
一起使用,这样可以将多次 IO
操作压缩为单次 IO
操作。
比如我们在使用 Python
的 Redis
客户端时执行事务时是要强制使用 pipeline
的。
pipe = redis.pipeline(transaction=true)
pipe.multi()
pipe.incr("books")
pipe.incr("books")
values = pipe.execute()
Redis 笔记(08)— 事务(一次执行多条命令、命令 watch/multi/exec/discard、错误处理)相关推荐
- c mysql并行多条sql_Linux上使用C语言执行多条SQL命令访问MYSQL数据库的有关问题...
Linux下使用c语言执行多条SQL命令访问mysql数据库的问题 Linux(Ubuntu10.04)系统,MYSQL5.1数据库,C语言! 数据库中有两张表:表A.B! 使用C语言从表A中查询数据 ...
- C++程序如何执行cmd命令;如何对cmd命令执行计时;如何一行执行多条cmd命令;
今天在做实验,测试各种压缩算法的性能时,遇到zstd算法在执行时不会自动输出压缩时间的问题,所以就想法子在cpp程序中给它执行再计时: C++程序如何执行cmd命令 直接上答案:system(要执行的 ...
- awk命令中执行多条shell命令
awk中使用的shell命令,有2种方法: 一.使用system() 二.使用print cmd | "/bin/bash" http://www.gnu.org/software ...
- pythonsubprocess执行多条shell命令_python中subprocess批量执行linux命令
可以执行shell命令的相关模块和函数有: os.system os.spawn os.popen --废弃 popen --废弃 commands --废弃,3.x中被移除 以上执行shell命令的 ...
- bat文件执行多条Linux命令,Js使用WScript.Shell对象执行.bat文件和cmd命令
WScript.Shell(Windows Script Host Runtime Library)是一个对象,对应的文件是C:/WINDOWS/system32/wshom.ocx,Wscript. ...
- 【大厂面试】面试官看了赞不绝口的Redis笔记(二)
文章目录 说明 四.Redis的其他功能 (一)慢查询 (二)pipeline (三)发布订阅 (四)Bitmap (五)HyperLogLog (六)GEO 五.Redis持久化的取舍和选择 (一) ...
- redis中的事务、lua脚本和管道的使用场景
https://blog.csdn.net/fangjian1204/article/details/50585080 事务 redis中的事务并不像mysql中那么完美,只是简单的保证了原子性.re ...
- Redis学习手册(事务)
一.概述: 和众多其它数据库一样,Redis作为NoSQL数据库也同样提供了事务机制.在Redis中,MULTI/EXEC/DISCARD/WATCH这四个命令是我们实现事务的基石.相信对有关系型数据 ...
- 执行多条SQL语句,执行数据库事务(可传入Sql参数)
上篇博客,实例介绍了一个事务执行多条SQL语句函数(int ExecuteSqlTran(List<String> SQLStringList))点击打开链接,方便之余又发现了它的缺陷-- ...
最新文章
- 重磅!明略发布数据中台战略和三大解决方案
- html媒体查询怎么把颜色换成图片,为网页中图片src添加媒体查询功能。
- 蓝桥杯2015初赛-星系炸弹-日期计算
- [转载]Flex 2.0 实现SWF全屏
- RDLC 格式化文本内容
- 第三方测评:GaussDB(for Redis)稳定性与扩容表现
- 计算机算法设计与分析 最长递增子序列
- Verilog常用算法-以2为求对数
- MOSSE相关滤波算法学习笔记
- 【软件测试】应用白盒测试实例
- TS中any与unknwon的区别
- 将figma的设计图上传到蓝湖
- 第二期DBA投票“今日必看”项目分析
- CSS实现进度条和订单进度条
- ubuntu下putty的安装及使用
- Android ContentProvider之联系人数据库及操作
- 【BULL中文文档】用于在 NodeJS 中处理分布式作业和消息的队列包
- 如何向瑞芯微平台添加驱动
- 网页要让它自适应各种手机屏幕宽度大小要怎么设置
- 什么是矩阵号系统?矩阵号系统的搭建及玩法分析