zoukankan      html  css  js  c++  java
  • 也谈乐观并发控制(转)

    add by zhj: 本文主要谈的是乐观并发控制,虽然乐观并发控制不太适用于并发写冲突很频繁的场景下,因为这样会导致事务回滚,需要用户重试retry,

    但是如果不用乐观并发控制的话,貌似也没有其它什么好的办法了,悲观锁并不能解决更新丢失的问题,比如本文中的例子,我们也可以想想Git

    遇到这种情况时是怎么处理的,其实Git也会像本文一样处理。为什么说悲观锁也不能完全解决更新丢失的问题呢?我们看下面的例子,两个用户

    张三,李四,他们两人可以更新同一条数据库记录,假设记录为(sex,age) = (‘male’, 25),下面的操作之后,李四的更新还是丢失了。这个例子其实

    跟下面讲的甲乙丙的例子差不多,都是会导致更新丢失的。解决办法就是用乐观并发控制。

    时间

    用户张三

    用户李四

    T1

    通过客户端查看记录

     

    T2

    服务端收到请求后,返回(‘male’, 25)

                             

    T3

     

    通过客户端查看记录

    T4

     

    服务端收到请求后,返回(‘male’, 25)

    T5

     

    在客户端编辑记录为(‘male’, 30),并提交服务端

    T6

     

    服务端收到后更新成功

    T7

    在客户端编辑记录为(‘female’, 25),并提交服务端

     

    T8

    服务端收到后更新成功

     

    T9

     

     

    另,本文作者认为乐观并发控制与MVCC是一回事,在此,我个人的观点还是乐观并发控制完全无锁,而MVCC一般与锁机制结合使用,至少在MySQL中是这样的,当修改数据时,会加X锁。

    原文:http://www.jayxu.com/2012/03/13/13326/

    今天酷壳上发布了一篇网友投稿的讨论MVCC的文章。写得很浅显,很明白。MVCC是每个接触数据库尤其是分布式互联网应用的开发人员应知应会的内容,而架构师更应该知道如何在悲观锁和乐观锁之间进行平衡与选择,这里不做展开,只想补充以下内容,来自于之前和现在的项目经验:

    乐观并发控制在web应用还有一种应用场景就是在前端页面事务无法控制到的位置通过version检查避免脏数据的覆盖操作。比如在悲观锁环境下,当多个用户在各自的浏览器上修改同一份数据的不同域时,由于事务延伸不到客户的浏览器上,因此当他们提交时,服务器、数据库会认为是多份独立的事务提交,将相继全部成功,最终导致最后提交的有效,前几次提交的数据都被最后一次提交的数据覆盖,形象一点:

    数据库原始数据


    +----+------+--------+-----+--------+

    | id | name | gender | age | height |

    +----+------+--------+-----+--------+

    | 1  | Jay  | male   | 29  | 1.88   |

    +----+------+--------+-----+--------+


    此时三个用户都打开了“编辑用户信息”页面,拿到了相同的数据,但是

    - 甲将性别改成“unknown”
    - 乙将年龄改成28
    - 丙将身高改成1.85
    假设他们依次提交,最终的结果将是


    +----+------+--------+-----+--------+

    | id | name | gender | age | height |

    +----+------+--------+-----+--------+

    | 1  | Jay  | male   | 29  | 1.85   |

    +----+------+--------+-----+--------+


    丙的提交生效,其他人的修改被脏数据覆盖

    如果使用乐观锁version机制,情况会有很大不同

    数据库原始数据


    +----+------+--------+-----+--------+---------+

    | id | name | gender | age | height | version |

    +----+------+--------+-----+--------+---------+

    | 1  | Jay  | male   | 29  | 1.88   | 1       |

    +----+------+--------+-----+--------+---------+


    还是按照上面的场景修改数据,还是按照上面的顺序提交,服务器会将version字段返回至客户端,客户端提交时也会带上version信息:

    - 甲提交,数据更新为


    +----+------+--------+-----+--------+---------+

    | id | name | gender | age | height | version |

    +----+------+--------+-----+--------+---------+

    | 1  | Jay  | unknown| 29  | 1.88   | 2       |

    +----+------+--------+-----+--------+---------+


    -
    乙提交,由于version已经更新为2,数据库认为有冲突(其实MVCC的version和传统的VCS是一样的,会有冲突发生),更新失败,抛异常,服务器提示“数据已被更新,请刷新后重试”,乙刷新获得甲更新后的数据,修改年龄为28,提交,数据更新为


    +----+------+--------+-----+--------+---------+

    | id | name | gender | age | height | version |

    +----+------+--------+-----+--------+---------+

    | 1  | Jay  | unknown| 28  | 1.88   | 3       |

    +----+------+--------+-----+--------+---------+


    - 丙提交,和乙一样,被告知“数据已被更新,请刷新后重试”,刷新,更新,提交,数据更新为


    +----+------+--------+-----+--------+---------+

    | id | name | gender | age | height | version |

    +----+------+--------+-----+--------+---------+

    | 1  | Jay  | unknown| 28  | 1.85   | 4       |

    +----+------+--------+-----+--------+---------+


    这应该是大家所预期的结果。而如果使用悲观锁要解决这个问题,只能在服务器端做额外的处理,辨识此次更新的字段,然后更新前查询一次数据库,获得最新的数据,仅更新发生变化的字段,然后提交。或者,页面就应该避免多字段大表单的提交,把每次可更新的内容进行拆分,比如现在几乎所有的SNS的用户信息更新页面都会按“基本信息”、“学校信息”、“就业信息”等分段保存(当然这么做的原因有很多,比如用户体验,对于一个长长的大表格,用户更能接受“少量多次”的提交方式,而且如果在保存前出现浏览器崩溃、死机等意外情况,未保存而需要重填的数据量不会很大。脏数据覆盖问题只是其中一个)

    最后补充两点实战经验

    - 如果需要在Hibernate中使用MVCC,直接在entity中定义一个int类型的字段,然后使用@Version修饰该字段
    -
    在真实环境中,若使用MVCC并且允许用户重复更新,每次页面提交后,应该将数据库最新的version值传回客户端。如果使用REST,直接放在response的header里是一种可行的做法

  • 相关阅读:
    为了可怜的成功率、缥缈的理想堵上这个人生,这对多数人来说都不值得(他以及他的家庭都会面临灾难)
    很多人在大学期间开发软件,接国企的案子,彻夜写程序;或者做家教、攒书、卖商品,难道那不是一种创业?
    为什么知乎上很多人都反对创业?(上战场的士兵如果先拿枪打打靶练练枪法,研究研究战术之后,战损比肯定要更好看一点)
    核心思想:创业一定要非常低调的进入市场
    核心思想:互联网创业十问?(大部分创业者是从学习借鉴成功者起步的,不需要把商业模式考虑完备,失败者没资格说趁着年轻...)4种失败的信号 good
    poj 3181 Dollar Dayz(求组成方案的背包+大数)
    核心思想:各位准创业者,不要再想什么蓝海市场了,沉下心来先干吧(试问连自己的生活都不敢去颠覆,谈什么颠覆互联网,颠覆传统行业,颠覆整个世界呢?)
    只想把技术做好,维持一份可观的收入,就精专一门;有创业想法,就全栈
    亢龙有悔,还是亢龙无悔?——是需要看情况的(兵无常势,水无常形)——看准了,就下本钱投入
    Uniconnection 连 mysql 有时会断线的
  • 原文地址:https://www.cnblogs.com/ajianbeyourself/p/4406882.html
Copyright © 2011-2022 走看看