Redis事务其实是一个乐观锁机制

数据库有事务,那Redis也有事务。有的人说Redis事务其实不算事务,应该叫具有命令打包功能。那么,元芳,你怎么看?

什么是事务

百科里面有这样一段话,事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。我们重点来关注下原子性和隔离性

原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。

隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

学过数据库的都明白,数据库的事务运行有三种模式:自动提交事务,显式事务,隐性事务。

自动提交事务:每条单独的语句都是一个事务,每个语句都隐含一个commit。一般执行单条的SQL操作都是自动提交事务。

显式事务:以begin transaction 开始,以commit 或 rollback 结束。一般我们代码中业务逻辑时开启事务对应的就是这种模式。

隐性事务: 在前一个事务完成时,新事务隐式启动,但每个事务仍以commit或rollback显示结束。

那么Redis是不是也有多种运行模式呢?狭隘地说其实并没有。

Redis事务

Redis事务顾名思义,就是Redis中的事务。Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:

批量操作在发送 EXEC 命令前被放入队列缓存。

收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行

事务执行过程其他客户端提交的命令请求不会插入到事务执行命令序列中

一个事务从开始到执行会经历以下三个阶段:开始事务,命令入队,执行事务。

看,Redis的事务就是这么简单粗暴。也就是说事务开启,N条Redis操作先入队,然后全部入队完毕后执行exec命令批量执行。其中如果有哪个操作失败或者错误了,剩下的操作继续执行,并且失败之前执行的操作也不会自动回滚,这个其实已经不保证执行的原子性了。注意,这点是和DB事务的最大差别。这也是很多人把Redis事务不叫做事务而只叫做具有命令打包功能的原因。引用一个例子来说明。

总结特点:

1.不支持回滚:没有实现错误直接回滚的功能;

2.不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有自动支持回滚;

3.隔离性:只保证了事务执行的隔离性。

为什么不支持回滚呢?其实官方还有个比较合理的说法,觉得还挺有意思:

只有当被调用的Redis命令有语法错误时,这条命令才会执行失败(在将这个命令放入事务队列期间,Redis能够发现此类问题),或者对某个键执行不符合其数据类型的操作:实际上,这就意味着只有程序错误才会导致Redis命令执行失败,这种错误很有可能在程序开发期间发现,一般很少在生产环境发现。

Redis已经在系统内部进行功能简化,这样可以确保更快的运行速度,因为Redis不需要事务回滚的能力。

watch命令其实是一个乐观锁机制

那既然称作是事务,肯定是要能支持回滚的吧,不然没有什么意义了。笔者认为回滚的话可以有两种方式。

其一,在操作命令被放入队列的时候也就是在exec之前就判断逻辑上的错误并不执行exec命令,则事务不会被执行;也可以配合DISCARD命令取消事务,放弃执行事务块内的所有命令。当然,这样的做法似乎对语法上的错误意义不大,因为操作入队的时候并没有直接被执行(版本不同存在争议),也就无法判断执行是否失败。(另一种说法是:如果将某个命令放入队列时发生错误,那么大多数客户端将会中止事务,并且丢弃这个事务。比如,由于INCR命令的语法错误,Redis根本就没有将这个命令放入事务执行队列。如果已经被放入了并执行exec,则不管是都存在错误,会将事务一直全部执行下去。);

其二,可以使用watch命令来手动回滚。值得一说的是,watch命令保证了执行的原子性(支持整个队列不执行=自动回滚)和隔离性。但其还是偏向于隔离性的支持,对于语法错误导致的失败仍然还是无法支持自动回滚的,这也再次印证了官方的那个观点:只有程序错误才会导致Redis命令执行失败,这种错误很有可能在程序开发期间发现,一般很少在生产环境发现

Redis Watch 命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

Redis使用WATCH命令实现事务的“检查再设置”(CAS)行为。

作为WATCH命令的参数的键会受到Redis的监控,Redis能够检测到它们的变化。在执行EXEC命令之前,如果Redis检测到至少有一个键被修改了,那么整个事务便会中止运行,然后EXEC命令会返回一个Null值,提醒用户事务运行失败。

我们引用一个例子来说明watch命令。

例子中用户A对key为balance的值进行了监控,之后用户B对balance进行了赋值操作,注意此时用户A监控的balance已经被其他用户修改了。而后用户A开启事务,对balance进行了一次减15的操作,执行exec。事务执行完毕我们查询balance结果,其值并没有改变。说明事务被中止或者说被回滚了。那么问题来了,事务中对debt的加15操作有执行成功吗?显然应该也是不执行的。

再次总结特点:

1.支持破坏隔离性时的回滚来同时保证原子性=Redis执行中的Redis自带的分布式乐观锁;

2.语法错误导致的原子性破坏还是不支持自动回滚(版本不同有争议); 在redis中,对于一个存在问题的命令,如果在入队的时候就已经出错,整个事务内的命令将都不会被执行(其后续的命令依然可以入队),如果这个错误命令在入队的时候并没有报错,而是在执行的时候出错了,那么redis默认跳过这个命令执行后续命令。

好了,很惊讶的是,这其实就是一个活生生的乐观锁的例子,回想我们之前Redis结合版本号实现的单体乐观锁,乐观锁的原理都一样。Redis用乐观锁机制实现了Redis事务,但是乐观锁的弊端也是存在的,在高并发的情况下,失败的可能性很高;不管是什么,合适的才是最好的,这个就留给观者去评判了。

Redis脚本也是事务型

Redis还有个脚本,根据定义,Redis脚本也是事务型的。我们可以想到我们之前用脚本实现的分布式锁。因此,可以通过Redis事务实现的功能,同样也可以通过Redis脚本来实现,而且通常脚本更简单、更快速。

那么大家都把Redis事务应用在什么场景呢?


参考资料:

教程

Redis的事务功能详解

Redis的事务讲解

原创文章,未经允许请勿转载。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351