前言
本文是MySQL使用innodb引擎涉及到的相关的锁
MySQL中有着Lock和Latch的概念,在数据库中,这两者都可以被称为“锁”,但是两者有着截然不同的含义。
如下图是对锁的详细分类:
其中:
- Latch一般称为闩锁(轻量级的锁),因为其要求锁定的时间必须非常短。若持续的时间长,则应用的性能会非常差,在InnoDB引擎中,Latch又可以分为mutex(互斥量)和rwlock(读写锁)。其目的是用来保证并发线程操作临界资源的正确性,并且通常没有死锁检测的机制。
- Lock的对象是事务,用来锁定的是数据库中的对象,如表、行。并且一般lock的对象仅在事务commit或rollback后进行释放(不同事务隔离级别释放的时间可能不同)。
下面我们深度介绍一下lock中的行锁和表锁。
不过在介绍行锁和表锁之前,我们先从各个维度对锁分类:
- 按锁的粒度划分:
- 表锁
- 行锁
- 按行锁的粒度划分
- 记录锁(Record Lock):单个行记录上的锁。
- 间隙锁(Gap Lock):锁定一个范围,但不包含记录本身。
- Next-Key Lock:Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身。
- 按锁的类型分裂
- 排他锁(写锁)
- 共享锁(读锁)
行锁
行级锁定最大的特点就是锁定对象的粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。 虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。
记录锁
总是会去锁住索引记录,如果InnoDB存储引擎表在建立的时候没有设置任何一个索引,那么这时InnoDB存储引擎会使用隐式的主键来进行锁定。锁定一个点。
- 记录共享锁
- 记录排他锁
间隙锁
- 它会封锁索引记录中的“缝隙”,让制其他事务在“缝隙”中插入数据。它锁定的是一个不包含索引本身的范围。锁定一个开区间。
- 只有在可重复读隔离级别才存在,在读提交隔离级别是不存在的。
- 间隙共享锁
- 间隙排他锁
Next-Key Lock
结合了Gap Lock和Record Lock的一种锁定算法。锁定的是一个左开右闭的区间。
- Next-Key共享锁
- Next-Key排他锁
表锁
普通表级锁
表示对当前操作的整张表加锁,它实现简单,资源消耗较少。但是锁的粒度非常大,容易引起并发问题。
意向锁
为了支持多粒度锁定,InnoDB 存储引擎引入了意向锁(Intention Lock)。
如果没有意向锁,当已经有人使用行锁对表中的某一行进行修改时,如果另外一个请求要对全表进行修改,那么就需要对所有的行是否被锁定进行扫描,在这种情况下,效率是非常低的;不过,在引入意向锁之后,当有人使用行锁对表中的某一行进行修改之前,会先为表添加意向互斥锁(IX),再为行记录添加互斥锁(X),在这时如果有人尝试对全表进行修改就不需要判断表中的每一行数据是否被加锁了,只需要通过等待意向互斥锁被释放就可以了。
- 意向共享锁(IS):事务想要在获得表中某些记录的共享锁,需要在表上先加意向共享锁。
- 意向互斥锁(IX):事务想要在获得表中某些记录的互斥锁,需要在表上先加意向互斥锁。