美文网首页MySQL
73-MySQL-事务-乐观锁和悲观锁

73-MySQL-事务-乐观锁和悲观锁

作者: 紫荆秋雪_文 | 来源:发表于2023-01-09 13:16 被阅读0次

从对待的态度来看锁的话,可以将锁分成乐观锁悲观锁,从名字中也可以看出这两种锁是两种看待数据并发的思维方式 。需要注意的是,乐观锁悲观锁并不是锁,而是锁的 设计思想

一、悲观锁(Pessimistic Locking)

悲观锁是一种思想,顾名思义,就是很悲观,对数据被其他事务的修改持保守态度,会通过数据库自身的锁机制来实现,从而保证数据操作的排它性
悲观锁总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会 阻塞 直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁,当其他线程想要访问数据时,都需要阻塞挂起。Java中 synchronizedReentrantLock 等独占锁就是悲观锁思想的实现。

1、实战1-秒杀案例

商品秒杀过程中,库存数量的减少,避免出现 超卖的情况。如:商品表中有一个字段为 stock 表示当前该商品的库存量。假设商品为华为 mate40,id为1001,stock=100个。如果不使用锁的情况下,操作方法如下

  • 第1步:查出商品库存
SELECT stock
FROM t_goods
WHERE id = 1001;
  • 第2步:如果库存大于 0,则根据商品信息生产订单
INSERT INTO t_order(good_id) VALUES (1001);
  • 第3步:修改商品的库存,num 表示购买商品数量
UPDATE t_goods
SET stock = stock - num
WHERE id = 1001;
  • 高并发环境下可能出现以下问题,其中线程B此时已经下单并且减完库存,这个时候线程A依然去执行step3,就造成了超卖
    高并发环境.png

2、解决超卖

使用悲观锁可以解决这个问题,商品信息从查询出来到修改,中间有一个生成订单的过程,使用悲观锁的原理就是,当我们在查询 t_goods 信息后就把当前的数据锁定,直到我们修改完毕后再解锁。那么整个过程中,因为数据被锁定了,就不会出现有第三者来对其进行修改了。而这样做的前提是 需要将要执行的 SQL 语句放在同一个事务中,否则达不到锁定数据行的目的

  • 第1步:查出商品库存,并且加排他锁
SELECT stock
FROM t_goods
WHERE id = 1001 FOR UPDATE ;
  • 第2步:如果库存大于 0,则根据商品信息生产订单
INSERT INTO t_order(good_id) VALUES (1001);
  • 第3步:修改商品的库存,num 表示购买商品数量
UPDATE t_goods
SET stock = stock - num
WHERE id = 1001;

小结

  • SELECT . . . FOR UPDATE是 MySQL 中悲观锁。此时在t_goods表中,id为 1001 的那条数据就被我们锁定了,其他的要执行 SELECT stock FROM t_goods WHERE id = 1001 FOR UPDATE语句的事务必须等本次事务提交之后才能执行。这样我们可以保证当前的数据不会被其它事务修改。

  • 注意:当执行 SELECT stock FROM t_goods WHERE id = 1001 FOR UPDATE语句之后,如果其他事务中执行SELECT stock FROM t_goods WHERE id = 1001语句,并不会受第一个事务的影响,仍然可以正常查询出数据。

  • 注意SELECT . . . FOR UPDATE语句执行过程中所有扫描的行都会被锁上,因此在MySQL中用悲观锁必须确定使用了索引,而不是全表扫描,否则将会把整个表锁住

  • 悲观锁不适用的场景较多,它存在一些不足,因为悲观锁大多数情况下依靠数据库的锁机制来实现,以保证程序的并发访问性,同时这样对数据库性能开销影响也很大,特别是长事务而言,这样的开销往往无法承受,这时就需要乐观锁

二、 乐观锁(Optimistic Locking)

乐观锁认为对同一数据的并发操作不会总发生,属于小概率事件,不用每次都对数据上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,也就是不采用数据库自身的锁机制,而是通过程序来实现。在程序上,我们可以采用 版本号机制 或者 CAS机制 实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量。在Java中 java.util.concurrent.atomic 包下的原子变量类就是使用了乐观锁的一种实现方式:CAS机制实现的。

1、 乐观锁的版本号机制

在表中设计一个 版本字段 version ,第一次读的时候,会获取 version 字段的取值。然后对数据进行更新或删除操作时,会执行 UPDATE ... SET version=version+1 WHERE version=version 。此时如果已经有事务对这条数据进行了更改,修改就不会成功。

2、乐观锁的时间戳机制

时间戳和版本号机制一样,也是在更新提交的时候,将当前数据的时间戳和更新之前取得的时间戳进行比较,如果两者一致则更新成功,否则就是版本冲突。
你能看到乐观锁就是程序员自己控制数据并发操作的权限,基本是通过给数据行增加一个戳(版本号或者时间戳),从而证明当前拿到的数据是否最新。

3、实战1-秒杀案例

  • 第1步:查出商品库存
SELECT stock
FROM t_goods
WHERE id = 1001;
  • 第2步:如果库存大于 0,则根据商品信息生产订单
INSERT INTO t_order(good_id) VALUES (1001);
  • 第3步:修改商品的库存,num 表示购买商品数量
UPDATE t_goods
SET stock = stock - num
WHERE id = 1001 and version = #{version};

小结

如果数据表是读写分离的,当 master 表中写入的数据没有及时同步到 slave 表中时,会造成更新一直失败的问题。此时需要强制读取 master 表中的数据(将 SELECT 语句放到事务中即可,这时候查询的就是 master 主库了)

  • 如果对同一条数据进行 频繁的修改 的话,那么就会出现这么一种场景,每次修改都只有一个事务能更新成功,在业务感知上面就有大量的失败操作。需要如下改善

  • 第1步:查出商品库存

SELECT stock
FROM t_goods
WHERE id = 1001;
  • 第2步:如果库存大于 0,则根据商品信息生产订单
INSERT INTO t_order(good_id) VALUES (1001);
  • 第3步:修改商品的库存,num 表示购买商品数量
UPDATE t_goods
SET stock = stock - num
WHERE id = 1001 and stock - num  > 0;

小结:乐观锁和悲观锁的适用场景

  • 乐观锁适合读操作多的场景,相对来说写的操作比较少。它的优点在于程序实现,不存在死锁问题,不过适用场景也会相对乐观,因为它阻止不了除了程序以外的数据库操作
  • 悲观锁适合写操作多的场景,因为写的操作具有排它性。采用悲观锁的方式,可以在数据库层面阻止其他事务对该数据的操作权限,防止读-写写-写的冲突
    image.png

相关文章

  • 73-MySQL-事务-乐观锁和悲观锁

    从对待锁的态度来看锁的话,可以将锁分成乐观锁和悲观锁,从名字中也可以看出这两种锁是两种看待数据并发的思维方式 。需...

  • mysql锁(十)innodb下的悲观锁和乐观锁

    ****悲观锁与乐观锁****悲观锁,也叫悲观并发控制,当事务A对某行数据应用了锁,并且当这个事务把锁释放后,其他...

  • 看完你就知道的乐观锁和悲观锁

    看完你就知道的乐观锁和悲观锁 Java 锁之乐观锁和悲观锁 [TOC] Java 按照锁的实现分为乐观锁和悲观锁,...

  • MySQL悲观锁与乐观锁的实现方案

    我们知道Mysql并发事务会引起更新丢失问题,解决办法是锁,所以本文将对锁(乐观锁、悲观锁)进行分析 悲观锁和乐观...

  • 乐观锁和悲观锁

    参考来源 深入理解乐观锁与悲观锁 乐观锁的一种实现方式——CAS mysql乐观锁总结和实践 乐观锁和悲观锁 悲观...

  • 锁的概述

    乐观锁与悲观锁 悲观锁 乐观锁和悲观锁的概念出自数据库,但在java并发包中也引入和类似的概念(乐观锁/悲观锁是一...

  • 并发参数

    悲观锁与乐观锁 悲观锁 synchronized和ReentrantLock等独占锁就是悲观锁思想的实现乐观锁一般...

  • 悲观锁/乐观锁

    乐观锁和悲观锁是并发控制主要采用的技术手段。为什么有了事务这东西,还需要乐观锁悲观锁? 比如抢票,假设余票只有1张...

  • CAS 与原子操作

    乐观锁与悲观锁 锁可以从不同的角度分类。其中,乐观锁和悲观锁是一种分类方式。 乐观锁:乐观锁又称为“无锁”。乐观锁...

  • 面试问题记录(一) Day50 2019-01-09

    并发中的常用锁,乐观锁和悲观锁,实现及使用 事务的特性,原理,spring如何实现事务 spring的实现机制,I...

网友评论

    本文标题:73-MySQL-事务-乐观锁和悲观锁

    本文链接:https://www.haomeiwen.com/subject/cwmpcdtx.html