按照锁的颗粒度来说,MySQL主要包含三种类型 (级别) 的锁定机制:

● 全局锁:锁定是整个database。由MySQL的SQL layer层实现的

● 表级锁:锁的是某个table。由MySQL的SQL layer层实现的

● 行级锁:锁的是某行数据,也可以锁定行之间的间隙。由某些存储引擎实现,比如InnDB。

按照锁的功能来说分为:共享锁和排她写锁。

按照锁的实现方式分为:悲观锁和乐观锁(使用某一版本列或者唯一列进去逻辑控制)

MYSQL锁_读锁


一、 表级锁

1、表锁
表锁有两种表现形式:表共享读锁(Table Read Lock)和 表独占写锁(Table Write Lock)

2、元数据锁
元数据锁不需要显式使⽤,在访问⼀个表的时候会被⾃动加上。元数据锁的作⽤是,保证读写的正确性。
可以想象⼀下,如果⼀个查询正在遍历⼀个表中的数据,⽽执⾏期间另⼀个线程对这个表结构做变更,删了⼀列,那么查询线程拿到的结果跟表结构对不上,肯定是不⾏的。
因此,在 MySQL 5.5 版本中引⼊了 元数据锁,当对⼀个表做增删改查操作的时候,加元数据读锁;当要对表做结构变更操作的时候,加 元数据写锁。
读锁之间不互斥,因此你可以有多个线程同时对⼀张执行查询。
读写锁之间、写锁之间是互斥的,⽤来保证变更表结构操作的安全性。
因此,如果有两个线程要同时给⼀个表加字段,其中⼀个要等另⼀个执⾏完才能开始执⾏。

session1: begin;--开启事务
session1: select * from tb_user;--加MDL读锁
session2: alter table tb_user add email varchar(20); -- 修改阻塞
session1:commit; --提交事务 或者 rollback 释放读锁
session2:Query OK, 0 rows affected (38.67 sec) --修改完成

3、 意向锁
InnoDB 支持多粒度的锁,允许表级锁和行级锁共存。一个类似于 LOCK TABLES ... WRITE 的语句会获得这个表的 x 锁。为了实现多粒度锁,InnoDB 使用了意向锁(简称 I 锁)。I 锁是表明一个事务稍后要获得针对一行记录的某种锁(s or x)的对应表的表级锁,有两种:
● 意向排它锁(简称 IX 锁)表明一个事务意图在某个表中设置某些行的 x 锁SELECT * FROM table_name WHERE ... FOR UPDATE
● 意向共享锁(简称 IS 锁)表明一个事务意图在某个表中设置某些行的 s 锁SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
意向锁的原则如下:
● 一个事务必须先持有该表上的 IS 或者更强的锁才能持有该表中某行的 S 锁
● 一个事务必须先持有该表上的 IX 锁才能持有该表中某行的 X 锁

-- 意向排它锁
session1 : begin ;
session1 : select * from tb_user where id = 1 for update ; -- 设置tb_user的排它锁
session2 : select * from tb_user where id = 1 for update ;  --阻塞
session1 : commit ;  --提交事务
-- 意向共享锁
session1 : begin ;
session1 : select * from tb_user where id = 1 LOCK IN SHARE MODE ; -- 设置tb_user的共享
session2 : select * from tb_user where id = 1  LOCK IN SHARE MODE ;  -- 查询

二、 行级锁
MySQL的⾏级锁,是由存储引擎来实现的,利⽤存储引擎锁住索引来实现的
InnoDB的⾏级锁,按照锁定范围来说,分为三种:
● 记录锁(Record Locks):锁定索引中⼀条记录。 id=1
● 间隙锁(Gap Locks):要么锁住索引记录中间的值,要么锁住第⼀个索引记录前⾯的值或者最后⼀个索引记录后⾯的值。
● Next-Key Locks:是索引记录上的记录锁和在索引记录之前的间隙锁的组合。
InnoDB的⾏级锁,按照功能来说,分为两种:
● 共享锁:允许⼀个事务去读⼀⾏,阻⽌其他事务获得相同数据集的排他锁。
● 排他锁(独占锁):允许获得排他锁的事务更新数据,阻⽌其他事务取得相同数据集的共享读锁(不是读)和排他写锁。

1、 记录锁
记录锁针对索引记录。举个例子, SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE; 会阻止其他所有事务插入、修改或者删除 t.c1 是 10 的行。
记录锁总是锁定索引记录,即使表没有索引(这种情况下,InnoDB会创建隐式的索引,并使用这个索引实施记录锁)

2、 共享锁与独占锁
InnoDB 实现了标准的行级锁,包括两种:共享锁(简称 s 锁)、排它锁(简称 x 锁)
● 共享锁允许持锁事务读取数据
● 排它锁允许持锁事务更新或者删除数据
如果事务 T1 持有行 r 的 s 锁,那么另一个事务 T2 请求 r 的锁时,会做如下处理:
● T2 请求 s 锁立即被允许,结果 T1 T2 都持有 r 行的 s 锁
● T2 请求 x 锁不能被立即允许
如果 T1 持有 r 的 x 锁,那么 T2 请求 r 的 x、s 锁都不能被立即允许,T2 必须等待T1释放 x 锁才行。

三、
1、死锁
所谓死锁(DeadLock)是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。表级锁不会产生死锁 , 只有行级锁才会产生死锁。

session1 : begin ; 
session1 : update tb_user set name = 'JIMY' where id = 1 ; 
session2 : begin ; 
session2 : update tb_user set name = 'JIMY' where id = 2 ;   --阻塞
session1 : update tb_user set name = 'Heim' where id = 2 ; 
session2 : 
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction