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 禁止在 multiexec 之间执行 watch 指令,而必须在 multi 之前做好盯住关键变量,否则会出错。

6. 事务结合管道使用

Redis 事务在发送每个指令到事务缓存队列时都要经过一次网络读写,当一个事务内部的指令较多时,需要的网络 IO 时间也会线性增长。所以通常 Redis 的客户端在执行事务时都会结合 pipeline 一起使用,这样可以将多次 IO 操作压缩为单次 IO 操作。

比如我们在使用 PythonRedis 客户端时执行事务时是要强制使用 pipeline 的。

pipe = redis.pipeline(transaction=true)
pipe.multi()
pipe.incr("books")
pipe.incr("books")
values = pipe.execute()

Redis 笔记(08)— 事务(一次执行多条命令、命令 watch/multi/exec/discard、错误处理)相关推荐

  1. c mysql并行多条sql_Linux上使用C语言执行多条SQL命令访问MYSQL数据库的有关问题...

    Linux下使用c语言执行多条SQL命令访问mysql数据库的问题 Linux(Ubuntu10.04)系统,MYSQL5.1数据库,C语言! 数据库中有两张表:表A.B! 使用C语言从表A中查询数据 ...

  2. C++程序如何执行cmd命令;如何对cmd命令执行计时;如何一行执行多条cmd命令;

    今天在做实验,测试各种压缩算法的性能时,遇到zstd算法在执行时不会自动输出压缩时间的问题,所以就想法子在cpp程序中给它执行再计时: C++程序如何执行cmd命令 直接上答案:system(要执行的 ...

  3. awk命令中执行多条shell命令

    awk中使用的shell命令,有2种方法: 一.使用system() 二.使用print cmd | "/bin/bash" http://www.gnu.org/software ...

  4. pythonsubprocess执行多条shell命令_python中subprocess批量执行linux命令

    可以执行shell命令的相关模块和函数有: os.system os.spawn os.popen --废弃 popen --废弃 commands --废弃,3.x中被移除 以上执行shell命令的 ...

  5. bat文件执行多条Linux命令,Js使用WScript.Shell对象执行.bat文件和cmd命令

    WScript.Shell(Windows Script Host Runtime Library)是一个对象,对应的文件是C:/WINDOWS/system32/wshom.ocx,Wscript. ...

  6. 【大厂面试】面试官看了赞不绝口的Redis笔记(二)

    文章目录 说明 四.Redis的其他功能 (一)慢查询 (二)pipeline (三)发布订阅 (四)Bitmap (五)HyperLogLog (六)GEO 五.Redis持久化的取舍和选择 (一) ...

  7. redis中的事务、lua脚本和管道的使用场景

    https://blog.csdn.net/fangjian1204/article/details/50585080 事务 redis中的事务并不像mysql中那么完美,只是简单的保证了原子性.re ...

  8. Redis学习手册(事务)

    一.概述: 和众多其它数据库一样,Redis作为NoSQL数据库也同样提供了事务机制.在Redis中,MULTI/EXEC/DISCARD/WATCH这四个命令是我们实现事务的基石.相信对有关系型数据 ...

  9. 执行多条SQL语句,执行数据库事务(可传入Sql参数)

    上篇博客,实例介绍了一个事务执行多条SQL语句函数(int ExecuteSqlTran(List<String> SQLStringList))点击打开链接,方便之余又发现了它的缺陷-- ...

最新文章

  1. 重磅!明略发布数据中台战略和三大解决方案
  2. html媒体查询怎么把颜色换成图片,为网页中图片src添加媒体查询功能。
  3. 蓝桥杯2015初赛-星系炸弹-日期计算
  4. [转载]Flex 2.0 实现SWF全屏
  5. RDLC 格式化文本内容
  6. 第三方测评:GaussDB(for Redis)稳定性与扩容表现
  7. 计算机算法设计与分析 最长递增子序列
  8. Verilog常用算法-以2为求对数
  9. MOSSE相关滤波算法学习笔记
  10. 【软件测试】应用白盒测试实例
  11. TS中any与unknwon的区别
  12. 将figma的设计图上传到蓝湖
  13. 第二期DBA投票“今日必看”项目分析
  14. CSS实现进度条和订单进度条
  15. ubuntu下putty的安装及使用
  16. Android ContentProvider之联系人数据库及操作
  17. 【BULL中文文档】用于在 NodeJS 中处理分布式作业和消息的队列包
  18. 如何向瑞芯微平台添加驱动
  19. 网页要让它自适应各种手机屏幕宽度大小要怎么设置
  20. 什么是矩阵号系统?矩阵号系统的搭建及玩法分析

热门文章

  1. 利用dom4j将实体类转换为对应的xml报文
  2. mysql备份psb文件怎么打开_Navicat for MySQL 数据备份教程
  3. Spring单实例、多线程安全、事务解析
  4. LLVM编译器基础架构与DragonEgg示例
  5. TensorFlow六种激活函数
  6. TVM Reduction降低算力
  7. 使用PCAST检测散度以比较GPU和CPU结果
  8. 用NVIDIA NsightcComputeRoofline分析加速高性能HPC的应用
  9. 视频动作定位的分层自关注网络:ICCV2019论文解析
  10. Git 头指针分离与 FETCH_HEAD