MySQL 的锁

排他锁和共享锁(按照锁的属性分)

  • 排他锁 ,也叫 写锁 简称 X锁,即事务 A 读数据对象加上 X锁以后,只能有事务 A 完成读取和修改操作,其他任何事物在此期间,都不能再加任何类型的锁,直到锁释放为停止。

  • 共享锁, 又叫 读锁,简称S锁,即事务 A 可以对对象添加 S 锁,则其他事务就只能再添加 S锁,而不能添加 X锁。

按照锁的颗粒分

  • 表锁:锁住的是整张表,下一个事务要访问,必须等上一个事务释放了锁才行。

  • 行锁:锁住的是表的某一行或者某几个行。

  • 记录锁:记录锁锁住的是表中的 一行 数据。命中条件是唯一索引。

  • 页锁:页锁是介于行锁和表锁之间,他锁定的是一组相邻的记录,锁定的范围是可调的。

  • 间隙锁:锁住的是表中的某一个区间。

  • 临键锁

乐观锁和悲观锁

悲观锁

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

悲观锁分为 共享锁排他锁

乐观锁

顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果冲突,则返回给用户异常信息,让用户决定如何去做。以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。

乐观所和悲观锁的比较

两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。

乐观锁比较适合于读多写少的情况,悲观锁比较适合写多读少的情况

悲观锁的实现,往往依靠数据库提供的锁机制

乐观锁不会刻意使用数据库本身的锁机制,而是依据数据本身来保证数据的正确性。

行锁、表锁、间隙锁

行锁

在下面的事务中,因为第一个窗口开启了手动的事务,所以当第一个数据更改了但是没有提交的时候,第二个窗口读到的还是老数据,所以这个就避免了 脏读 这种情况。

image

此时,我们在第二个窗口,执行更新语句

UPDATE a SET a.age=15 WHERE a.id=1;

此时,第二个窗口会一直阻塞,而不会执行,只有当从第一个窗口执行完 COMMIT 命令的时候,第二个窗口才执行。

表锁

某些情况下,如果使用 OR 作为连接关键字,会使索引失效,而把行锁变成表锁,如在表一中,更改id=1 or id=2 的时候,在第二个窗口里,更新 id=3 的值也不行。
image

间隙锁

如果索引不连续,比如 id 为 1、3、8 这种,执行如下语句。

UPDATE a SET a.age=15 WHERE a.id>0 AND a.id<5;

因为选择的范围是 0-5 中间,那么如果插入 2,那么显然不行,这就是间隙锁,他把这个范围内的都锁住了,你往这个范围内插入都不行

参考文献

[1] https://www.jianshu.com/p/d2ac26ca6525

posted @ 2021-07-10 00:27  沧海一声笑rush  阅读(59)  评论(0编辑  收藏  举报