MySQL 按锁的粒度可以细分为行级锁、页级锁和表级锁。
我们可以将锁粒度理解成锁范围。
表级锁为表级别的锁定,会锁定整张表,可以很好的避免死锁,是 MySQL 中最大颗粒度的锁定机制。
一个用户在对表进行写操作(插入、删除、更新等)时,需要先获得写锁,这会阻塞其它用户对该表的所有读写操作。没有写锁时,其它读取的用户才能获得读锁,读锁之间是不相互阻塞的。
表级锁最大的特点就是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。当然,锁定颗粒度大带来最大的负面影响就是出现锁定资源争用的概率会很高,致使并发度大打折扣。
不过在某些特定的场景中,表级锁也可以有良好的性能。例如,READ LOCAL 表级锁支持某些类型的并发写操作。另外,写锁也比读锁有更高的优先级,因此一个写锁请求可能会被插入到读锁队列的前面(写锁可以插入到锁队列中读锁的前面,反之读锁则不能插入到写锁的前面)。
使用表级锁的主要是 MyISAM,MEMORY,CSV 等一些非事务性存储引擎。
尽管存储引擎可以管理自己的锁,MySQL 本身还是会使用各种有效的表级锁来实现不同的目的。例如,服务器会为诸如 ALTER TABLE 之类的语句使用表级锁,而忽略存储引擎的锁机制。
页级锁是 MySQL 中比较独特的一种锁定级别,在其他数据库管理软件中并不常见。
页级锁的颗粒度介于行级锁与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力同样也是介于上面二者之间。另外,页级锁和行级锁一样,会发生死锁。
页级锁主要应用于 BDB 存储引擎。
行级锁的锁定颗粒度在 MySQL 中是最小的,只针对操作的当前行进行加锁,所以行级锁发生锁定资源争用的概率也最小。
行级锁能够给予应用程序尽可能大的并发处理能力,从而提高需要高并发应用系统的整体性能。虽然行级锁在并发处理能力上面有较大的优势,但也因此带来了不少弊端。
由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也就更多,带来的消耗自然也就更大。此外,行级锁也最容易发生死锁。所以说行级锁最大程度地支持并发处理的同时,也带来了最大的锁开销。
行级锁主要应用于 InnoDB 存储引擎。
随着锁定资源颗粒度的减小,锁定相同数据量的数据所需要消耗的内存数量也越来越多,实现算法也会越来越复杂。不过,随着锁定资源颗粒度的减小,应用程序的访问请求遇到锁等待的可能性也会随之降低,系统整体并发度也会随之提升。
MySQL 这 3 种锁的特性可大致归纳如下:
表级锁 | 行级锁 | 页级锁 | |
---|---|---|---|
开销 | 小 | 大 | 介于表级锁和行级锁之间 |
加锁 | 快 | 慢 | 介于表级锁和行级锁之间 |
死锁 | 不会出现死锁 | 会出现死锁 | 会出现死锁 |
锁粒度 | 大 | 小 | 介于表级锁和行级锁之间 |
并发度 | 低 | 高 | 一般 |
从上述特点可见,很难笼统的说哪种锁更好,只能具体应用具体分析。
从锁的角度来说,表级锁适合以查询为主,只有少量按索引条件更新数据的应用,如 Web 应用。而行级锁更适合于有大量按索引条件,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统。