MySQL - 锁

  • Last updated on 2020-05-27
  • 23922
Mysql  

一、什么是锁

锁是数据库系统区别于文件系统的一个关键特性。锁机制用于管理对共享资源的并发访问。

 

二、MySQL 不同存储引擎支持的锁机制

存储引擎 支持的锁类型
Myisam 表锁
Innodb 行锁、表锁
Memory 表锁
BDB 页锁、表锁

 
表锁:直接锁住的是一个表,开销小,加锁快,不会出现死锁的情况,锁定粒度大,发生锁冲突的概率更高,应对并发能力最低。(因为加锁了,所以经常需要等待)

行锁:直接锁住的是一条记录,开销大,加锁慢,发生锁冲突的概率较低,应对并发能力很高。

页锁:锁住的一个页面,在 InnoDB 中一个页面为16KB,它的开销介于表级锁和行级锁中间,也可能会出现死锁,锁定粒度也介于表级锁和行级锁中间,应对并发能力介于表级锁和行级锁中间。

 

三、InnoDB 存储引擎中的锁

InnoDB 支持的是行级锁和表级锁。但是 InnoDB 实际上是实现了 6 种锁。

1、实现了两种标准的 行级锁,分别是 共享锁、排他锁

2、实现了两种标准的 表级锁,分别是 意向共享锁、意向排他锁

3、实现了两种抽象的锁,乐观锁、悲观锁。(这两种锁并不是真实存在的)

 

四、InnoDB 存储引擎中 各种锁的加锁示例

1、加共享锁示例:

  1. -- 事务 T1
  2. BEGIN;
  3. START TRANSACTION;
  4. select * from user where id = 1 LOCK IN SHARE MODE;
  5. -- COMMIT;
  1. -- 事务 T2
  2. -- 不加锁的查询 (可以查询到)
  3. -- SELECT * from user where id = 1;
  4. -- 不加锁的更新 (不可以更新)
  5. -- UPDATE `user` set age = 29 where id = 1;
  6. -- 加共享锁的查询 (可以查询到)
  7. -- SELECT * from user WHERE id = 1 LOCK IN SHARE MODE;
  8. -- 加排他锁的查询 (不可以查询)
  9. -- SELECT * from user WHERE id = 1 FOR UPDATE;

  如果在事务 T1 中对行记录加了共享锁,那么其他事务 T2,不论加没加锁,都不能更新,直到事务 T1 释放锁。

  如果在事务 T1 中对行记录加了共享锁,事务 T2 是没有加锁的查询,或者加的是共享锁的查询,则可以查询到结果。

  如果在事务 T1 中对行记录加了共享锁,事务 T2 是加了排它锁的查询,则暂时不能查询,直到事务 T1 释放锁。

 
2、加排他锁示例

  1. -- 事务T1
  2. BEGIN;
  3. START TRANSACTION;
  4. select * from user where id = 1 FOR UPDATE;
  5. COMMIT;
  1. -- 事务 T2
  2. -- 不加锁的查询 (可以查询到)
  3. -- SELECT * from user where id = 1;
  4. -- 不加锁的更新 (不可以更新)
  5. -- UPDATE `user` set age = 29 where id = 1;
  6. -- 加共享锁的查询 (不可以查询到)
  7. -- SELECT * from user WHERE id = 1 LOCK IN SHARE MODE;
  8. -- 加排他锁的查询 (不可以查询到)
  9. -- SELECT * from user WHERE id = 1 FOR UPDATE;

  如果在事务 T1 中对行记录加了排他锁,那么其他事务T2,如果是不加锁的查询,是可以查询到结果的,但如果是加锁的查询或更新,则不允许操作,直到事务 T1 释放锁。

注:凡是更新、删除、插入操作,Mysql都会默认给这个操作加上排他锁,所以这里只演示查询操作的。

 
3、加意向共享锁

  对一个数据行加共享锁(S),首先 InnoDB 会先找到这张表,对该表加意向共享锁(IS)之后,再对该数据行添加共享锁。意向共享锁和意向排他锁都是系统自动添加和自动释放的,整个过程无需人工干预。

 
4、加意向排他锁

  对一个数据行加排他锁(X),首先 InnoDB 会先找到这张表,对该表加意向排他锁(IX)之后,再对该数据行添加排它锁。意向共享锁和意向排他锁都是系统自动添加和自动释放的,整个过程无需人工干预。

 
5、关于乐观锁和悲观锁的说明

乐观锁和悲观锁并不是真实存在的锁,它们只是抽象出来的,对锁的使用情况的描述。

 
6、悲观锁

  悲观锁的特点是先获取锁,再进行业务操作,即“悲观”的认为获取锁是非常有可能失败的,因此要先确保获取锁成功再进行业务操作。通常所说的“一锁二查三更新”即指的是使用悲观锁。通常来讲在数据库上的悲观锁需要数据库本身提供支持,即通过常用的select … for update 操作来实现悲观锁。

 
7、乐观锁

  乐观锁的特点是先进行业务操作,不到万不得已不去拿锁。即“乐观”的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿一下锁就好。乐观锁在数据库上的实现完全是逻辑的,不需要数据库提供特殊的支持。

 

 



Top