MySQL锁定机制分析--表级锁定

为了保证数据的一致性,任何数据库都存在锁定机制。MySQL作为最常用的数据库,自然也不例外。 MySQL使用的主要存储引擎分为以下几种:

  • MyISAM
  • InnoDB
  • NDB Cluster
  • Maria
  • Falcon
  • Memory
  • Archive
  • Merge
  • Federated

其中,使用最多最广泛的就是MyISAM和InnoDB,这里介绍锁定机制也主要探讨这2种存储引擎。 MySQL的锁定机制有3个级别:

  • 行级锁定(row-level)
  • 表级锁定(table-level)
  • 页级锁定(page-level)

##行级锁定

属于最小的锁定粒度。因为锁定粒度很小,所以发生资源争用的概率也是最小的,能应对App最大的并发处理需求,提升性能。但也正是由于粒度小,使得每次获取和释放锁的时候需要的操作和消耗的资源也变得更多,也最容易发生死锁。使用这种锁定的引擎主要是MyISAM、Memory、CSV等。

##表级锁定

表级锁定是MySQL中锁定粒度最大的一种锁定。实现的逻辑最简单,系统处理锁使用的资源也最少,可以很好的避免死锁问题。当然,相对于行级锁定,并行处理的能力也由于对整个表的一次性锁定而大打折扣。使用这种锁定的引擎为InnoDB、NDB Cluster。

##页级锁定

属于MySQL中一种特殊的锁定机制。锁定某一类查询页的时候会用到(并不常用),粒度介于以上2种锁定之间,其他特性也相对如此。这种锁定方式为BDB的锁定形式。 先简单看一下表级锁定。 一般来讲,表级锁定分为读锁和写锁。MySQL通过4个队列来维护这2种锁定的信息:

  • 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)

很简单,从字面上就可以知道这些队列分别的公用。

##读锁

一个新的Client Requset Resources(Read读锁),需要满足以下2个条件:

  • 请求锁定的资源上没有写锁。
  • 写锁等待队列(Pending write-lock queue)中没有更高优先级(high-level-priority)的写锁在等待(获取资源)。

如果满足了以上的2个条件,那么当前Client立即获取资源,并加上读锁。

如果任一条件没有得到满足,这个请求会被迫进入等待队列(Pending read-lock queue)中等待资源的释放。

##写锁

当Client Requset Resources(Write写锁)的时候,MySQL首先会Check Current write-lock queue是否已经有锁定相同资源的信息存在。然后是检查Pending write-lock queue,如果有锁已经存在,则进入等待队列。

MyISAM引擎使用的锁机制完全是由MySQL提供的表级锁定实现的。下面以MyISAM引擎为例,对显式的加锁做一个演示:

  1. 显式给qqlist表加读锁,session之间的操作未被阻塞。 readlock1

  2. 更新操作:当前拥有锁的session遇到加锁的错误,其他session的操作被阻塞。 readlock2

  3. 释放读锁。其他session获取资源,操作顺利执行。 readlock3

  4. 获取local read,其他线程的insert操作未被阻塞(Concurrent Insert特性)。 readlock4

  5. 显式给qqlist表加写锁,其他session的读操作被阻塞。 writelock1

  6. 释放写锁。其他session获取资源,操作顺利执行。 writelock2

  7. 通过DDL(Alter table)获取WRITE_ALLOW_READ类型的写锁,其他session的读操作未被阻塞。 writelock3