MySQL 的表级锁定主要分为两种类型,一种是读锁定,另一种是写锁定。


        在MySQL 中,主要通过四个队列来维护这两种锁定:两个存放当前正在锁定中的读和写锁定信息,另外两个存放等待中的读写锁定信息,如下:


        Current read-lock queue (lock->read)


        Pending read-lock queue (lock->read_wait)


        Current write-lock queue (lock->write)


        Pending write-lock queue (lock->write_wait)


        当前持有读锁的所有线程的相关信息都能够在Current read-lock queue 中找到,队列中的信息按照获取到锁的时间依序存放。而正在等待锁定资源的信息则存放在Pending read-lock queue 里面,另外两个存放写锁信息的队列也按照上面相同规则来存放信息。


        虽然对于使用者来说MySQL 展现出来的锁定(表锁定)只有读锁定和写锁定这两种类型,但是在MySQL 内部实现中却有多达13 种锁定类型,由系统中一个枚举量(thr_lock_type)定义,各值描述如下:


锁定类型

说明

IGNORE

当发生锁请求的时候内部交互使用,在锁定结构和队列中并不会有任何信息存储

UNLOCK

释放锁定请求的交互用所类型

READ

普通读锁定

WRITE

普通写锁定

READ_WITH_SHARED_LOCKS

在Innodb 中使用到,由如下方式产生如:SELECT ... LOCK IN SHARE MODE

READ_HIGH_PRIORITY

高优先级读锁定

READ_NO_INSERT

不允许Concurent Insert 的锁定

WRITE_ALLOW_WRITE

这个类型实际上就是当由存储引擎自行处理锁定的时候,mysqld 允许其他的线程再获取读或者写锁定,因为即使资源冲突,存储引擎自己也会知道怎么来处理

WRITE_ALLOW_READ

这种锁定发生在对表做DDL(ALTER TABLE ...)的时候,MySQL 可以允许其他线程获取读锁定,因为MySQL 是通过重建整个表然后再RENAME 而实现的该功能,所在整个过程原表仍然可以提供读服务

WRITE_CONCURRENT_INSERT

正在进行Concurent Insert 时候所使用的锁定方式,该锁定进行的时候,除了READ_NO_INSERT 之外的其他任何读锁定请求都不会被阻塞

WRITE_DELAYED

在使用INSERT DELAYED 时候的锁定类型

WRITE_LOW_PRIORITY

显示声明的低级别锁定方式, 通过设置LOW_PRIORITY_UPDAT = 1 而产生

WRITE_ONLY

当在操作过程中某个锁定异常中断之后系统内部需要进行CLOSE TABLE 操作,在这个过程中出现的锁定类型就是WRITE_ONLY


1、读锁定


        一个新的客户端请求在申请获取读锁定资源的时候,需要满足两个条件:


        (1)、请求锁定的资源当前没有被写锁定;


        (2)、写锁定等待队列(Pending write-lock queue)中没有更高优先级的写锁定等待;


        如果满足了上面两个条件之后,该请求会被立即通过,并将相关的信息存入Current read-lock queue 中,而如果上面两个条件中任何一个没有满足,都会被迫进入等待队列Pending read-lock queue中等待资源的释放。


2、写锁定


        当客户端请求写锁定的时候,MySQL 首先检查在Current write-lock queue 是否已经有锁定相同资源的信息存在。


        如果Current write-lock queue 没有,则再检查Pending write-lock queue,如果在Pending write-lock queue 中找到了,自己也需要进入等待队列并暂停自身线程等待锁定资源。反之,如果Pending write-lock queue 为空,则再检测Current read-lock queue,如果有锁定存在,则同样需要进入Pending write-lock queue 等待。当然,也可能遇到以下这两种特殊情况:


        (1)、请求锁定的类型为WRITE_DELAYED;


        (2)、请求锁定的类型为WRITE_CONCURRENT_INSERT 或者是WRITE_ALLOW_WRITE, 同时Current read lock 是READ_NO_INSERT 的锁定类型。


        当遇到这两种特殊情况的时候,写锁定会立即获得而进入Current write-lock queue 中。如果刚开始第一次检测就Current write-lock queue 中已经存在了锁定相同资源的写锁定存在,那么就只能进入等待队列等待相应资源锁定的释放了。


3、读请求和写锁优先级规则


        读请求和写等待队列中的写锁请求的优先级规则主要为以下规则决定:


        (1)、除了READ_HIGH_PRIORITY 的读锁定之外,Pending write-lock queue 中的WRITE 写锁定能够阻塞所有其他的读锁定;


        (2)、READ_HIGH_PRIORITY 读锁定的请求能够阻塞所有Pending write-lock queue 中的写锁定;


        (3)、除了WRITE 写锁定之外,Pending write-lock queue 中的其他任何写锁定都比读锁定的优先级低。


        写锁定出现在Current write-lock queue 之后,会阻塞除了以下情况下的所有其他锁定的请求:


        (1)、在某些存储引擎的允许下,可以允许一个WRITE_CONCURRENT_INSERT 写锁定请求


        (2)、写锁定为WRITE_ALLOW_WRITE 的时候,允许除了WRITE_ONLY 之外的所有读和写锁定请求


        (3)、写锁定为WRITE_ALLOW_READ 的时候,允许除了READ_NO_INSERT 之外的所有读锁定请求


        (4)、写锁定为WRITE_DELAYED 的时候,允许除了READ_NO_INSERT 之外的所有读锁定请求


        (5)、写锁定为WRITE_CONCURRENT_INSERT 的时候,允许除了READ_NO_INSERT 之外的所有读锁定请求


        


参考:《MySQL性能调优与架构设计》