事务

Redis事务的相关命令有MULTI,EXEC,DISCARD,WATCH。它们允许在一个步骤中执行一组命令,并有两个重要的保证:

  • 事务中的所有命令都会被序列化并按顺序执行。在执行Redis事务的过程中,不会发生由另一个客户端发出的请求被服务的情况。这保证命令作为一个单独的隔离的操作被执行。

  • 无论是所有的命令都被处理还是没有命令被处理,Redis事务都是原子的。EXEC命令触发事务中所有命令的执行,因此如果在调用MULTI命令之前,客户端在事务上下文中失去与服务器的连接,则不执行任何操作,相反如果调用EXEC命令, 所有的操作都被执行。在使用仅追加文件时,Redis确保使用单个写入(2)系统调用将事务写入磁盘。但是,如果Redis服务器崩溃或被系统管理员以某种强制的方式杀死,可能只有部分操作被注册。Redis将在重新启动时检测到这种情况,并会在出现错误时退出。使用redis-check-aof工具可以删除部分事务修复仅追加文件,以便服务器可以重新启动。

从版本2.2开始,Redis允许为上述两项提供额外保证,采用与check-and-set(CAS)操作非常相似的乐观锁定形式。这将在本页后面记录。

用法

使用MULTI命令进入Redis事务。该命令总是以OK回应。此时用户可以发出多个命令。Redis不会执行这些命令,而是将它们排队。EXEC被调用后,所有的命令都会被执行。

调用DISCARD而不是刷新事务队列并将退出事务。

以下示例以原子方式递增key foo和bar。

> MULTI
OK
> INCR foo
QUEUED
> INCR bar
QUEUED
> EXEC
1) (integer) 1
2) (integer) 1

EXEC返回一个响应数组,其中每个元素都是事务中单个命令的响应,顺序与命令的发出顺序相同。

当Redis连接处于MULTI请求的上下文中时,所有命令将以字符串QUEUED(从Redis协议的角度作为状态回复发送)进行回复。EXEC被调用时,排队的命令被简单地安排执行。

事务中的错误

事务过程中,可能会遇到两种命令错误:

  • 命令可能无法排队,因此在调用EXEC之前可能会出现错误。例如,命令可能在语法上是错误的(参数数量错误,错误的命令名称…),或者可能存在某些关键条件,如内存不足的情况(如果服务器配置为使用maxmemory 指示)。

  • 例如,因为我们针对具有错误值的key执行操作(例如,针对字符串值调用list操作),所以命令可能在调用EXEC后失败。

通过检查排队命令的返回值,客户端用于检测EXEC调用之前发生的第一种错误:如果命令使用QUEUED进行响应,则它已正确排队,否则Redis将返回错误。如果排队命令时发生错误,大多数客户端将中止该事务并放弃它。

然而,从Redis 2.6.5开始,服务器会记住在累积命令期间发生错误,并拒绝执行EXEC期间返回错误的事务,并自动丢弃该事务。

在Redis 2.6.5之前,行为只是在成功排队的命令子集内执行事务,以防客户端调用EXEC而不管以前的错误。新的行为使得将事务与流水线混合变得更加简单,因此整个事务可以一次发送,一次读取所有回复。

EXEC之后发生的错误不是以一种特殊的方式处理的:即使某些命令在事务中失败,也会执行所有其他命令。

这在协议层面更加清晰。 在以下示例中,即使语法正确,一个命令在执行时也会失败:

Trying 127.0.0.1…
Connected to localhost.
Escape character is ‘^]’.
MULTI
+OK
SET a 3
abc
+QUEUED
LPOP a
+QUEUED
EXEC
*2
+OK
-ERR Operation against a key holding the wrong kind of value

EXEC返回two-element批量字符串回复,其中一个是OK代码,另一个是-ERR回复。客户端库需要找到一种明智的方式将错误提供给用户。

需要注意的是,即使命令失败,队列中的所有其他命令也会被处理–Redis不会停止命令的处理。

另一个例子,再次使用telnet协议使用Wire协议,可以显示语法错误是如何报告的:

MULTI
+OK
INCR a b c
-ERR wrong number of arguments for ‘incr’ command

这次由于语法错误,错误的INCR命令根本没有排队。

为什么Redis不支持回滚?

如果您有关系数据库背景,Redis命令在事务处理期间可能会失败,但Redis将执行其余事务而不是回滚事务,这可能对您来说看起来很奇怪。

但是,对于这种行为有很好的意见:

  • 如果使用错误的语法调用Redis命令(并且在命令排队期间无法检测到问题),或者针对保存错误数据类型的key,则Redis命令可能会失败:这意味着实际上,失败的命令是编程错误的结果, 以及在开发过程中很可能检测到的一种错误,而不是在生产中。

  • Redis内部简化且速度更快,因为它不需要回滚功能。

反对Redis观点的一个观点是错误发生了,但是应该指出的是一般情况下,回滚并不能避免编程错误。例如,如果查询将key增加2而不是1,或增加错误的key,则回滚机制无法提供帮助。鉴于没有人能够挽救程序员的错误,并且Redis命令失败所需的错误类型不太可能进入生产环境,所以我们选择了不支持错误回滚的更简单快捷的方法。

放弃命令队列

DISCARD可用于中止交易。在这种情况下,不执行任何命令并且连接状态恢复正常。

> SET foo 1
OK
> MULTI
OK
> INCR foo
QUEUED
> DISCARD
OK
> GET foo
“1”

乐观锁定使用check-and-set

WATCH用于为Redis事务提供check-and-set(CAS)行为。

监视key被监视以检测对它们的改变。如果在EXEC命令之前至少修改了一个监视的key,则整个事务中止,并且EXEC返回Null答复以通知事务失败。

例如,假设我们需要将key的值自动递增1(让我们假设Redis没有INCR)。

第一次尝试可能如下:

val = GET mykey
val = val + 1
SET mykey $val

只有当我们有一个客户端在给定时间内执行操作时,这才能可靠地工作。如果多个客户端尝试在大约同一时间递增key,则会出现竞争状况。例如,客户端A和B将读取旧值,例如10,这两个客户端的值将递增为11,最后将SET作为key的值。所以最终的值将是11而不是12。

感谢WATCH,我们能够很好地模拟这个问题:

WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC

使用上面的代码,如果存在竞争条件,并且另一个客户端在我们对WATCH的调用和我们对EXEC的调用之间的时间内修改了val的结果,则事务将失败。

我们只需要重复这次的操作,希望这次我们不会得到新的竞争。这种形式的锁定称为乐观锁定,是一种非常强大的锁定形式。在许多用例中,多个客户端将访问不同的key,因此碰撞不太可能发生 - 通常不需要重复该操作。

WATCH说明

那么WATCH真的是什么? 这是一个使EXEC有条件的命令:只有在没有任何WATCHed key被修改的情况下,我们才会要求Redis执行事务。 (但是它们可能会被事务中的同一个客户端改变而不会中止它,更多的是这个)否则,事务根本不会进入。(请注意,如果您WATCH易失性key并且Redis在您WATCH该key后过期了该key,那么EXEC将继续工作。更多的是这个。)

WATCH可以多次调用。简单地说,所有的WATCH调用都将具有WATCH从调用开始发生变化的效果,直到EXEC被调用。您也可以将任意数量的key发送到单个WATCH调用。

当调用EXEC时,无论事务是否中止,所有key都是UNWATCHed。此外,当客户端连接关闭时,所有都会被UNWATCHed。

也可以使用UNWATCH命令(无参数)来刷新所有watch的key。

有时候,我们乐观地锁定了几个key,这很有用,因为可能我们需要执行一个事务来改变这些key,但是在读完了key的当前内容之后我们不想继续。发生这种情况时,我们只需调用UNWATCH,以便连接可以自由用于新事务。

使用WATCH来实现ZPOP

举一个很好的例子来说明如何使用WATCH来创建新的原子操作,否则Redis不支持实现ZPOP,即以原子方式从排序集合中以较低分数弹出元素的命令。这是最简单的实现:

WATCH zset
element = ZRANGE zset 0 0
MULTI
ZREM zset element
EXEC

如果EXEC失败(即返回空回复),我们只需重复该操作。

Redis脚本和事务

根据定义,Redis脚本是事务性的,因此您可以使用Redis事务执行的所有操作都可以通过脚本完成,通常脚本将更简单快捷。

这种重复是由于在Redis 2.6中引入了脚本,而事务早已存在。然而,我们不可能在短时间内取消对事务的支持,因为即使不采用Redis脚本编写,仍然可以避免竞争状况,尤其是因为Redis事务的实施复杂性最低,这在语义上似乎是恰当的。

然而,在不远的将来,我们将看到整个用户群只是使用脚本,这并非不可能。如果发生这种情况,我们可能会弃用并最终删除事务。

官方API文档:http://www.redis.cn/topics/transactions.html

redis——redis事务相关处理相关推荐

  1. Redis的事务:相关命令 watch 与mysql事务的区别

    Redis事务的概念: Redis 事务的本质是一组命令的集合. 事务支持一次执行多个命令,一个事务中所有命令都会被序列化.在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不 ...

  2. Redis 服务器管理相关命令

    客户端相关 查看客户端列表 CLIENT LIST 自2.4.0可用. 时间复杂度:O(N) N是客户端连接数量. 语法:CLIENT LIST 说明: Redis CLIENT LIST 命令用于返 ...

  3. Redis : redis事务

    Redis的事务功能详解 MULTI.EXEC.DISCARD和WATCH命令是Redis事务功能的基础. Redis事务允许在一次单独的步骤中执行一组命令,并且可以保证如下两个重要事项: >R ...

  4. Redis中事务的实现流程

    场景 Centos中Redis的下载编译与安装(超详细): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103967334 Re ...

  5. Redis面试题相关知识整理

    Redis面试题相关知识整理 1.Redis的应用场景 2.Redis的特点 3.Redis对各种数据类型的操作 4.Redis的持久化机制 5.Redis的缓存穿透/缓存击穿/缓存雪崩问题 6.Re ...

  6. Redis 实用技术——事务

    引言 redis的事务不像关系型数据库的事务那样完整. "快"是redis的特征,在事务管理的过程中,使用muti命令开启事务块,当输入多条命令后,再使用exec命令执行事务块中的 ...

  7. Redis的事务(一次执行多条命令,防止重读重写)

    在关系型数据库中,事务是指一组命令的集合,这组命令构成了一个原子操作,这个操作要么全部执行成功,要么全部执行失败.而在非关系型数据库 Redis 中并非这样- Redis 中的事务同样也是一组命令的集 ...

  8. mysql 事务回滚_简短截说阐述redis中事务的使用

    我们知道,在关系型数据库中,比如mysql,如果要使用事务,首先向数据库服务器发送 BEGIN ,然后执行各个相互一致的写操作和读操作,最后,用户可以选择发送 COMMIT 来确认之前所做的修改,或者 ...

  9. redis—redis事务

    文章目录 Redis事务的概念 总结: Redis事务的三个阶段 Redis事务相关命令 Redis事务支持隔离性吗? Redis为什么不支持事务回滚? Redis事务其他实现 ----------- ...

最新文章

  1. 查看linux电脑总内存,如何查看Linux系统中的内存使用情况的命令呢?
  2. [设计模式] ------ 抽象工厂模式
  3. linux android ndk
  4. (转载)二进制与三进制的妙用
  5. Nginx高可用-Keepalived
  6. HTML5 开源游戏引擎 LayaAir
  7. 163接收邮件服务器pop3,pop3设置(163邮箱imap pop3设置)
  8. ST-LINK驱动的安装(有图 超详细)
  9. 搭建GOOGLE企业邮箱以及域名解析全攻略
  10. android绑定两个ip,安卓手机模拟器如何多开切换IP防封号的最新方法介绍
  11. 维修管理系统微信小程序部署流程
  12. 机器学习十大算法原理总结
  13. Aligning Domain-Specific Distribution and Classifier for Cross-Domain Classification from Multiple
  14. 汽车维修企业管理【12】
  15. gif透明背景动画_在找gif制作app?分享一个GIF制作神器,视频、图片通通可以变GIF...
  16. 鸿蒙系统官网电脑版,华为鸿蒙pc系统
  17. 商用机器人底盘的秘密
  18. 计算机音乐如何复制到手机桌面,电脑上的歌怎么传到手机上
  19. javascript socket
  20. Kubernetes Ingress and Services 故障排查

热门文章

  1. 52 FI配置-财务会计-固定资产-折旧-定义终止值代码
  2. post python爬虫_小白学 Python 爬虫(17):Requests 基础使用
  3. js 正则是否包含某些字符串_js 判断字符串中是否包含某个字符串(转载)
  4. Linux系统中使用pdb调试python代码
  5. 期望E==>加权均值(每个元素×它们各自的概率)
  6. 深度残差收缩网络:(一)背景知识
  7. Oracle 分页与排序功能的4个查询语句
  8. Segnet的caffe训练环境搭建
  9. shell脚本:实现文件覆盖写入、文件内容追加写入
  10. 电脑断网分析(故障排查手册)- 自救篇