avatar

目录
MySQL 中都有哪些锁?

MySQL 为了解决并发、数据安全等问题,使用了锁机制,下面就从不同角度归纳总结一下 MySQL 中的锁的分类

一. 按锁的粒度划分

按锁的粒度来划分,可以把数据库锁分为 表级锁行级锁

  • 表级锁:MySQL 中锁定粒度最大的一种锁,会对当前操作的整张表加锁。其特点是加锁快,不会发生死锁。缺点是锁冲突的概率最高,并发度最低。MyISAM 和 InnoDB 引擎都支持。

  • 行级锁:MySQL 中锁粒度最小的一种锁,只针对当前进行操作的行加锁。InnoDB 引擎支持行级锁。由于行级锁能大大降低数据库操作的行冲突概率,因此并发度高。但是由于加锁之前要经历搜索阶段,因此其加锁开销大,加锁慢,会出现死锁。

    InnoDB 支持的行级锁包括以下几种:

    1. Record Lock: 对索引项加锁,锁定符合条件的行。在加锁事务未提交前,其他事务无权修改和删除。
    2. Gap Lock:间隙锁,锁定符合条件的记录的范围(对第一条记录前的间隙或最后一条记录后的间隙加锁),不包含索引项本身。加锁事务未提交或回滚之前,其他事务不能在锁范围内插入数据。
    3. Next-key Lock: Record Lock 和 Gap Lock 结合在一起,称为 Next-key Lock. 锁定索引项本身和索引范围。

二. 从读写角度划分

表级锁和行级锁从是否共享读写角度又可以分为共享锁排他锁

  • 共享锁:又称为读锁,读取数据时创建的锁。当一个事务获取了读锁,其他事务可以读取数据,可以再在该数据上再加读锁,但是不能获取排他锁,即不能修改该数据。在 SELECT 语句中可以通过显式使用 lock in share mode 来强制获取共享锁。除此之外,绝大部分读操作并不会对数据记录加锁。
  • 排他锁:又称为写锁。update/delete/insert 操作所涉及的数据默认都会加上排他锁。在一个事务对数据加上排他锁后,其他事务不能再对该数据加任何类型的锁,而获取了排他锁的事务对该数据是可读可写。对于查询语句,可以使用 select xxx for update 显式的加排他锁。

此外值得一说的是,InnoDB 中还有以下两个表级锁:

  • 意向共享锁 (IS) : 表示事务准备给数据行加入共享锁,在加锁前必须先获得该表的 IS 锁。
  • 意向排他锁 (IX) : 表示事务准备给数据行加入排他锁,在加锁前必须先获得该表的 IX 锁 。

意向锁是 InnoDB 引擎自动加的,无须用户干预。

三. 从是否真正加锁的角度划分

谈到数据库的锁,很多人都会不由自主地提起乐观锁悲观锁,而对这二者的使用,其实是要结合具体业务场景的。

  • 悲观锁:通常在高并发情况下,多个线程对相同数据的访问,从保证数据安全的角度出发,是要加锁的,上述的行级锁和表级锁等等锁机制都是真正加锁锁住了数据的,是属于 悲观锁 的范畴。

  • 乐观锁:与悲观锁相对的 乐观锁,其实并不是真的加锁。乐观锁的实现类似于 Java 中的 CAS 机制,通过比较一个版本号来实现数据的安全更新。版本号的乐观锁的具体实现思路是:

    在数据表中加上一个数据版本号 version 字段,表示数据被修改的次数。当数据被修改时,version 值会 +1。当某一线程要更新数据时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读取到的 version 值与当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功。

文章作者: JanGin
文章链接: http://jangin.github.io/2021/07/03/what-are-the-locks-in-MySQL/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 JanGin's BLOG

评论