MySQL

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

2023-01-09  本文已影响0人  紫荆秋雪_文

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

一、悲观锁(Pessimistic Locking)

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

1、实战1-秒杀案例

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

SELECT stock
FROM t_goods
WHERE id = 1001;
INSERT INTO t_order(good_id) VALUES (1001);
UPDATE t_goods
SET stock = stock - num
WHERE id = 1001;

2、解决超卖

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

SELECT stock
FROM t_goods
WHERE id = 1001 FOR UPDATE ;
INSERT INTO t_order(good_id) VALUES (1001);
UPDATE t_goods
SET stock = stock - num
WHERE id = 1001;

小结

二、 乐观锁(Optimistic Locking)

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

1、 乐观锁的版本号机制

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

2、乐观锁的时间戳机制

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

3、实战1-秒杀案例

SELECT stock
FROM t_goods
WHERE id = 1001;
INSERT INTO t_order(good_id) VALUES (1001);
UPDATE t_goods
SET stock = stock - num
WHERE id = 1001 and version = #{version};

小结

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

SELECT stock
FROM t_goods
WHERE id = 1001;
INSERT INTO t_order(good_id) VALUES (1001);
UPDATE t_goods
SET stock = stock - num
WHERE id = 1001 and stock - num  > 0;

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

上一篇 下一篇

猜你喜欢

热点阅读