Mysql-10-乐观锁和悲观锁

Mysql-10-乐观锁和悲观锁

1. 乐观锁和悲观锁

首先说明,乐观锁和悲观锁都是针对读(select)来说的。

也就是一句话:读用乐观锁,写用悲观锁。

1.1 乐观锁

  • 总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新时会判断其他线程在这之前有没有对数据进行修改
  • 一般会使用版本号机制CAS操作实现
  • 乐观锁适用于多读的应用类型,这样可以提高吞吐量
  1. version方式:一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。

    • 当线程A要更新数据值时,在读取数据的同时也会读取version值,
    • 在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。

核心SQL代码:

1
update table set x=x+1, version=version+1 where id=#{id} and version=#{version};
  1. CAS操作方式:compare and swap 或者 compare and set,涉及到三个操作数,数据所在的内存值,预期值,新值。
    • 当需要更新时,判断当前内存值与之前取到的值是否相等,若相等,则用新值更新,若失败则重试,一般情况下是一个自旋操作,即不断的重试。

1.2 悲观锁

  • 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
  • 传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制

首先说明,乐观锁和悲观锁都是针对读(select)来说的。

案例:

某商品,用户购买后库存数应-1,而某两个或多个用户同时购买,此时三个执行程序均同时读得库存为“n”,之后进行了一些操作,最后将均执行update table set 库存数=n-1,那么,很显然这是错误的。

解决:

  1. 使用悲观锁(其实说白了也就是排他锁

    |– 程序A在查询库存数时使用排他锁(select * from table where id=10 for update)

    |– 然后进行后续的操作,包括更新库存数,最后提交事务。

    |– 程序B在查询库存数时,如果A还未释放排他锁,它将等待……

    |– 程序C同B……

  2. 使用乐观锁(靠表设计和代码来实现)

    |– 一般是在该商品表添加version版本字段或者timestamp时间戳字段

    |– 程序A查询后,执行更新变成了:
    *update table set num=num-1 where id=10 and version=23*

    这样,保证了修改的数据是和它查询出来的数据是一致的(其他执行程序肯定未进行修改)。当然,如果更新失败,表示在更新操作之前,有其他执行程序已经更新了该库存数,那么就可以尝试重试来保证更新成功。为了尽可能避免更新失败,可以合理调整重试次数(阿里巴巴开发手册规定重试次数不低于三次)。

总结:对于以上,可以看得出来乐观锁和悲观锁的区别:

  • 悲观锁实际使用了排他锁来实现(select \** for update**)。文章开头说到,innodb加行锁的前提是:必须是通过索引条件来检索数据,否则会切换为表锁。

    因此,悲观锁在未通过索引条件检索数据时,会锁定整张表。导致其他程序不允许“加锁的查询操作”,影响吞吐。故如果在查询居多的情况下,推荐使用乐观锁。

    加锁的查询操作”:加过排他锁的数据行在其他事务中是不能修改的,也不能通过for updatelock in share mode的加锁方式查询,但可以直接通过select ...from...查询数据,因为普通查询没有任何锁机制

  • 乐观锁更新有可能会失败,甚至是更新几次都失败,这是有风险的。所以如果写入居多,对吞吐要求不高,可使用悲观锁。

参考博客 :

https://blog.csdn.net/localhost01/article/details/78720727?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight

https://blog.csdn.net/L_BestCoder/article/details/79298417

打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2019-2022 Zhuuu
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信