天道不一定酬所有勤
但是,天道只酬勤

深入理解乐观锁与悲观锁

开发十年,就只剩下这套架构体系了!!

数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。

乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。

无论是悲观锁还是乐观锁,都是人们定义出来的概念,可以认为是一种思想。其实不仅仅是关系型数据库系统中有乐观锁和悲观锁的概念,像memcache、hibernate、tair等都有类似的概念。

针对于不同的业务场景,应该选用不同的并发控制方式。所以,不要把乐观并发控制和悲观并发控制狭义的理解为DBMS中的概念,更不要把他们和数据中提供的锁机制(行锁、表锁、排他锁、共享锁)混为一谈。其实,在DBMS中,悲观锁正是利用数据库本身提供的锁机制来实现的。

下面来分别学习一下悲观锁和乐观锁。

悲观锁

当我们要对一个数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发。

这种借助数据库锁机制在修改数据之前先锁定,再修改的方式被称之为悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)。

在关系数据库管理系统里,悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)是一种并发控制的方法。它可以阻止一个事务以影响其他用户的方式来修改数据。如果一个事务执行的操作都某行数据应用了锁,那只有当这个事务把锁释放,其他事务才能够执行与该锁冲突的操作。
悲观并发控制主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。

悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度(悲观),因此,在整个数据处理过程中,将数据处于锁定状态。 悲观锁的实现,往往依靠数据库提供的锁机制 (也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)

在数据库中,悲观锁的流程如下:

在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)。

如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。 具体响应方式由开发者根据实际需要决定。

如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。

其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常。

MySQL InnoDB中使用悲观锁

Hollis为了防爬虫以及未经授权的恶意转载,此处内容已被作者隐藏,请输入验证码查看内容
验证码:
请关注本站微信公众号,回复“验证码”,获取验证码。在微信里搜索“Hollis”或者“hollischuang”或者微信扫描右侧二维码都可以关注本站微信公众号。

参考资料

维基百科-乐观并发控制

维基百科-悲观并发控制

mysql悲观锁总结和实践

mysql乐观锁总结和实践

乐观锁与悲观锁

(全文完) 欢迎关注『Java之道』微信公众号
赞(10)
如未加特殊说明,此网站文章均为原创,转载必须注明出处。HollisChuang's Blog » 深入理解乐观锁与悲观锁
分享到: 更多 (0)

评论 12

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #1

    最后一句没理解遇到什么问题,请赐教

    面向对象的旅者4年前 (2016-01-07)回复
    • 多事务并发,如果做不好事务隔离,就有可能导致脏读、不可重复读、幻读等问题。http://www.hollischuang.com/archives/900

      HollisChuang4年前 (2016-01-07)回复
    • 是指aba的问题,修改了数据库值再改回来你就不知道了,起不到锁的效果

      国家公务员4年前 (2016-01-07)回复
  2. #2

    最后一句我也没理解到,
    当两个事务并发时,事务一提交后,如果事务二可以看见事务一提交的version,那么就可以看见事务一修改后的所有数据,这不会有问题吧,如果事务二看不见事务一提交的version,那么事务二因为version字段值不是最新的会更新失败. version是一致赠加的,aba问题不会遇到吧,除非version值空间很小, 乐观锁问题还是有点疑惑???

    weixin5000443103年前 (2016-08-28)回复
    • 乐观锁不能防范脏数据

      visitor5554951293年前 (2016-12-30)回复
      • 为什么?帮忙解释一下呗

        bigzuo11个月前 (01-21)回复
  3. #3

    不会出现aba问题,因为有版本号,即使改回原值,也可以知道到底有没有修改过。

    chen_h_hui3年前 (2017-03-30)回复
  4. #4

    最后依据 是 有点 问题吧,update version 本身就存在行锁,回写 数据库 是 不会存在 问题的。

    Ever2年前 (2017-08-17)回复
  5. #5

    乐观锁本身是update操作,id加version同样会触发数据库锁,为什么说乐观锁不会加锁呢?

    姜小超2年前 (2018-04-27)回复
  6. #6

    但如果直接简单这么做,还是有可能会遇到不可预期的结果,例如两个事务都读取了数据库的某一行,经过修改以后写回数据库,这时就遇到了问题。 这句是不是有问题? mysql rr级别下写操作会默认加行锁 , 更新语句的执行是有顺序的 , 通过版本号的控制 , 第二个更新操作会失败 , 不会发生ABA的问题吧.

    红裙翠襦2年前 (2018-05-07)回复
  7. #7

    不是每次update都会将version+1吗,怎么会有ABA问题

    清澈的瞳孔2年前 (2018-05-09)回复
  8. #8

    很好

    呆子8个月前 (04-09)回复

HollisChuang's Blog

联系我关于我