msyql 锁的分类
1. 以锁的粒度维度划分:
1.1 表锁
1.1.1 全局锁:加上全局锁之后,整个数据库只能允许读,不允许做任何写操作。是加在数据库上的锁,使用场景:一般是对整库做数据备份时使用。
1.1.2 元数据锁/MDL锁:基于表的元数据加锁,加锁后整张表不允许其他事务操作。用于更改表结构时使用,当一张表创建/删除一个索引、修改一个字段的名称/数据类型、增加/删除一个表字段等这类情况
1.1.3 意向锁:是InnoDB为了支持多粒度的锁,为了兼容行锁、表锁设计的,如给一条数据加了行锁,此时要加表锁,为了方便判断,在加行锁时设置了表级别的意向锁,加快判断速度。
1.1.4 自增锁/AUTO-INC锁:为了提升自增ID的并发插入性能而设计的,使用自增id时使用的锁。可以通过innodb_autoinc_lock_mode
参数控制。
1.1.4.1 innodb_autoinc_lock_mode = 0
:传统模式: 只能允许一个事务获取自增锁,另一个事务需要等待
1.1.4.2 innodb_autoinc_lock_mode = 1
:连续模式:对于能够提前确认数量的插入语句,则不会再获取自增锁,因为会直接分配范围自增值。采用的是轻量级锁Mutex-Lock来防止自增锁重复分配。
1.1.4.3 innodb_autoinc_lock_mode = 2
:交错模式:不同事务之间插入数据时,自增列的值是交错插入的。
1.2 页面锁
1.3 行锁
1.3.1 记录锁/record锁:也就是行锁,一条记录和一行数据是同一个意思。能命中索引数据,则加行锁,无法命中则加表锁。
如:select * from user where id = 1 for update; 获取行级别的排他锁;
select * from user where id = 1 lock in share mode; 获取行级别的共享锁
1.3.2 间隙锁/Gap锁:InnoDB 中解决幻读问题的一种锁机制。间隙锁:遵循 左右开区间,当对一个不存在的数据加锁后,默认就是锁定前后两条数据之间的区间,当其他事务再尝试向该区间插入数据时,就会陷入阻塞,只有当持有间隙锁的事务结束后,才能继续执行插入操作。间隙锁是根据检索条件向下寻找最靠近检索条件的记录值A作为左区间,向上寻找最靠近检索条件的记录值B作为右区间,即锁定的间隙为(A,B)
如:表中存在id为1,2,3,6,9的数据, 此时执行 select * from user where id = 7 lock in share mode;则间隙锁是加在了{4~9}之间,此时想插入一条id = 7的数据,就会出现等待,直到sql1 提交完成,sql2 才能执行成功。
1.3.2.1 插入意向锁也是间隙锁的一种,同时是隐式锁,不能主动加锁。当事务执行插入语句阻塞时,就会生成一个插入意向锁,表示当前事务相对一个区间插入数据。多个事务要想一个区间插入数据时,插入意向锁是不会排斥其他事务的,也就是插入意向锁也是一种共享锁。
1.3.3 临建锁/Next-Key锁:间隙锁的升级版,同时具备记录锁+间隙锁的功能。临键锁是加锁后,即锁定左开右闭的区间,也会锁定当前行数据。
如:表中存在id为1,2,3,6,9的数据,此时执行 select * from user where id = 6 lock in share mode;则间隙锁是加在了{3~6}之间,此时想插入一条id = 5的数据,就会出现等待,直到sql1 提交完成,sql2 才能执行成功。
2. 以互斥性的维度划分:
2.1 共享锁/s锁:不同事务之间不会相互排斥、可以同时获取的锁。
2.2 排他锁/x锁:不同事务之间会相互排斥、同时只能允许一个事务获取的锁。
2.3 共享排他锁/SX锁:MySQL 5.7中新引入的锁,主要解决SMO带来的问题。
3. 以操作类型的维度划分:
3.1 读锁:查询数据时使用的锁
3.2 写锁:执行插入、删除、修改、DDL语句时使用的锁。
4. 以加锁方式的维度划分:
4.1 显示锁:编写SQL语句时,手动指定加锁的粒度。
4.2 隐式锁:执行SQL语句时,根据隔离级别自动为SQL操作加锁。
5. 以思想的维度划分:
5.1 乐观锁:每次执行前认为自己会成功,因此先尝试执行,失败时再获取锁。
5.2 悲观锁:每次执行前都认为自己无法成功,因此会先获取锁,然后再执行。