mysql 系列:锁和它的运用

前言

数据库是一个允许多用户、多会话、多线程访问的系统。为了在并发访问中能保证数据的一致性和完整性,一般会使用事务来做控制,外加锁来作为辅助手段。所以今天整理了一下锁的相关知识,看看它在事务里是怎么配合使用的。

锁的分类

我们先来看下锁的分类及其作用有哪一些,以便能更好的分析运用场景。

乐观/悲观锁

乐观锁:在读取数据时会假设各个事务互不影响,它们会处理好属于自己的那部分数据。如果在更新数据时,发现有其他事务修改了属于自己的数据,则会回滚之前的一切操作。

悲观锁:采取了先获取锁再访问的保守策略,如果已经有其他事务获取了锁,则必须等待锁释放才能继续。

共享/排它锁

共享锁:又称读锁,当前事务在读取时,允许其他事务并发读取,但不允许其他事务上排它锁,必须等自己释放了才能继续。

排它锁:又称写锁,在写锁占有时,如果其他事务想上读写锁,则得排队等待。

表锁/行锁

表锁:在操作数据时,直接将整张表锁住,操作粒度很大,很容易让其他事务在等待,但不会产生死锁。

行锁:针对的是行记录的并发控制,锁粒度很细,能支持高并发,但是不排除会有死锁情况产生。在 mysql 里行锁依赖索引实现,如果没有索引存在,则会直接进行表锁

其中,行锁还细分出了下面几种锁:

记录锁:只锁住某一条记录。当对唯一索引(包括主键)进行精确查询时,会使用记录锁。

间隙锁:当使用范围查询时,会对符合条件的区间数据上锁。在涉及到普通索引(即不是唯一索引)的查询时,都会使用间隙锁。

Next-key 锁:临建锁,可以理解为 记录锁 + 间隙锁。当对唯一索引进行范围查找或对唯一索引进行查找但结果不存在时(可以理解为锁住不存在的记录),会使用临建锁。

上面的间隙锁、临建锁有效的防止了事务幻读情况产生,避免了在查找期间有数据新增或删除。

意向锁

意向锁是属于表锁的一种,它仅仅表示一种操作意向。当我们使用粒度比较小的行锁时,在检测是否有锁时,需要一行一行的检查,效率较低。

有了意向锁之后,则不需一行一行的排查,只需检测对应的意向锁即可。

意向锁有意向共享锁,以及意向排它锁。mysql 规定事务在上共享/排它锁时,必须能先获取到兼容的意向锁,否则必须等待锁的释放。

例如当前数据上已有意向共享锁,如果此时其他事务想上排它锁,则是不兼容的,必须等待释放。关于意向锁和共享/排它锁的兼容性表如下:

意向共享锁 意向排它锁
共享锁 兼容 互斥
排它锁 互斥 互斥

MVCC

MVCC 并不属于锁操作里的东西,但是它是事务隔离级别里会运用到的技术,并且由于它有类似快照数据的功能,所以使用 MVCC 时能很大程度的减少锁的使用,减少了并发冲突。具体可以看看这篇文章:MVCC

事务里锁的运用

在之前的文章事务解释里我们谈到了事务的隔离性,而事务的隔离性离不开锁的运用,所以现在就让我们来看看具体的使用吧。

可重复读

可重复读使用的是 MVCC 快照,所以在读取数据时大多数时候不需要使用锁。

但使用了 UPDATE, DELETE,或 SELECT with FOR UPDATE(排它锁) 或 FOR SHARE(共享锁),则会根据下面的情况来使用锁:

  • 在唯一索引上精确查找某条记录时,使用记录锁
  • 对于其他的搜索,InnoDB 将会锁定扫描到的索引范围,使用间隙锁或临建锁来防止幻读的产生

读提交

也是使用 MVCC 机制来读取数据,不过在使用 UPDATE, DELETE,或 SELECT with FOR UPDATE(排它锁) 或 FOR SHARE(共享锁)时和上面的机制不一样,当存储引擎将筛选到的记录交给 mysql server 层后,会对不相干的数据进行解锁,所以不会涉及间隙锁或临建锁。

它们只会在做外键约束检查和重复键检查时使用到。

由于间隙锁的禁用,可能会出现幻读现象。

未提交读

在 mysql 的 innodb 存储引擎里做 SELECT操作不会做任何锁动作,如果是 myisam 存储引擎,则会上共享锁。

如果使用UPDATE, DELETE,或 SELECT with FOR UPDATE(排它锁) 或 FOR SHARE(共享锁)则和读提交一样的原则。

可序列化读

可序列化读在使用 select 时,一般会自动的转化为 SELECT ...
FOR SHARE(共享锁) ,以保证读写序列化。

总结

本文介绍了锁的分类以及锁在事务里的使用,大多数时候 mysql 的事务都是会自动进行锁动作,并不需要我们干涉。

所以当我们在使用 SELECT with FOR UPDATE(排它锁) 或 FOR SHARE(共享锁)等显示上锁语句时要特别注意性能损耗,有可能产生间隙锁、临建锁导致不相干的记录也会被阻塞等待

上一篇:redis 系列:总结篇


下一篇:kali linux下最简单的一种arp断网攻击