数据库中的悲观锁和乐观锁

这两种类型的锁都是为了解决更新丢失的问题。

1、什么是丢失更新?

考虑这个场景:在一个web应用中,用户1检索某表的数据行R到编辑页面,用户2也检索数据R到编辑页面,用户1修改了R的字段A1,然后提交修改(注意,这里的提交是将用户编辑页面的所有字段都更新到数据库,哪怕该字段没有变化),用户2这时修改了R的字段A2,然后执行了类似的全量更新提交。不难发现,这种情况下,用户1对于字段A1的修改会被用户2的操作覆盖掉。这时,我们称丢失了修改。

有人会认为,由于我们在提交修改时,也会将没有变化的字段也更新,如果只是更新变化的字段就不会出现这个问题。实际上,这里的问题在于用户2在编辑页面修改数据时,所面对的数据已经不是当前数据库中最新的版本,可能有其它用户已经将某些数据做了修改。考虑在一个电商系统中,对于某个刚支付完成的订单1,客户检索该订单到编辑页面,库管检索该订单到编辑页面,他们看到的该订单都是已支付的状态。然后,顾客将订单的状态置为取消,然后提交修改(这里只提交对状态字段的修改),而库管看到已支付的订单,然后就将发货,并将订单状态置为了已发货。这也是一个丢失修改的例子。

这里问题的关键在于后面的用户在修改时,不知道从他查出数据到提交更新两个操作期间,可能有其它用户对数据做了修改。这期间的更新没有被用户看到,这种,情况称为丢失更新。

2、悲观锁和乐观锁

为了解决这个问题,需要用到数据库的锁机制,大致两种思路:悲观锁(pessimistic locking)和乐观锁(optimistic locking)。

2.1 悲观锁

悲观锁就是在尝试更新某记录之前,先给该记录加锁。在上面的例子场景中,就是在将记录检索到编辑页面时,对该记录加锁。之所以叫悲观锁,就是因为这个思路的出发点比较悲观,认为坏的事情(在数据检索到编辑页面之后,修改提交之前,会有其他用户也修改页面上的数据)会发生。

其实,加锁很简单。比如之前在将记录载入编辑页面时,用的查询语句是select cols from table where condition1,那么加锁后的语句就是select cols from table where condition1 for update nowait。其中,for update代表加锁,nowait表示如果待加锁对象上已经有锁,导致没法加锁时,立即返回“资源正忙,无法加锁”的信息,并执行结束。如果没有指定nowait,则会一直等着待加锁对象上当前有的锁释放,然后加锁成功时,才会执行结束。

这样加锁之后,在对该对象持有锁期间,对其进行更新,并提交,就能够保证没有其他用户能够修改加锁的对象。这就是悲观锁。

2.2 乐观锁

相反的,乐观锁的出发点就是认为坏的事情不会发生。这样,在用户将记录载入编辑页面时不会进行提前加锁。转而在更新提交时采用一些技巧,来避免丢失更新。

可以想象的技巧,大概如下:
(1)给记录添加版本号标识,每次更新时对该标识加一,只有版本号大于数据库中记录原来的版本号时,记录才会被成功更新。
(2)在更新条件中,添加旧值筛选到where条件,这样,如果期间有其它用户更新,会导致筛选不出记录,更新失败。比如,上面电商的例子中,库管发货的更新脚本可以写为update table set status=“已发货” where condition and status=“已支付”。这样,如果有其它用户将订单状态改为“取消”,就会更新0行,从而避免丢失更新。
(3)在提交更新前采用select for update(也就是锁)检查。这里不是在记录检索到修改页面的时候加锁(这时悲观锁的做法),而是在用户提交修改的时候,通过加锁来检查该记录这期间是否被其他用户修改。如果该记录没有变化,就提交修改;如果有变化,就提示用户记录状态有改变。

有人可能会认为最后一种方式实际是悲观锁的方式,但实际上,因为没有提前加锁,只是更新提交时加锁检查,所以,也是乐观锁。

3、适用场景

两种锁机制的适用场景,从它们的名字就能看出来。悲观锁适用于冲突出现概率较高的场景,悲观锁应用于对象的时间较长,容易导致阻塞。所以,web应用中,用户读取数据后,可能很久才会提交更新,这样会导致锁长时间占用,影响效率。所以web应用中,不适合采用悲观锁。而乐观锁适用于冲突出现概率较低的场景。

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

推荐阅读更多精彩内容