全局锁
一般适用于:数据库的备份以及迁移
flush tables with read lock
加上全局锁之后,数据库就属于只读的状态。其他操作都会被阻塞,直到全局锁被释放。
unlock tables
表级锁定
普通表锁:
//表级别的共享锁,也就是读锁;
lock tables table_name read;
//表级别的独占锁,也就是写锁;
lock tables table_name write;
unlock tables
元数据锁(MDL)
在数据库中不需要直接加上元数据锁:
-
在MySQL中当我们进行CURD时,会自动给这个表加上MDL写锁
-
当我们进行结构操作时,会自动加上MDL写锁
在语句执行的时候会立即加锁,但是在语句执行完毕之后不会立即释放,一直到事务提交才会释放锁
在数据库被大量调用的时候,轻易不要去改变数据库的结构包括增加一个字段或者去增加一个索引,会造成严重的业务问题
意向锁
在innodb对数据加锁之前会先在表级加上一个意向锁
//先在表上加上意向共享锁,然后对读取的记录加共享锁
select ... lock in share mode;
//先表上加上意向独占锁,然后对读取的记录加独占锁
select ... for update;
意向共享锁和意向独占锁是表级锁,不会和行级的共享锁和独占锁发生冲突,而且意向锁之间也不会发生冲突,只会和共享表锁(lock tables ... read)和独占表锁(lock tables ... write)发生冲突。
当一个被插上意向锁,说明这个表中是有锁的。
AUTO-INC 锁
在插入数据时,会加一个表级别的 AUTO-INC 锁,然后为被 AUTO_INCREMENT
修饰的字段赋值递增的值,等插入语句执行完成后,才会把 AUTO-INC 锁释放掉。
其他事务的如果要向该表插入语句都会被阻塞,从而保证插入数据时,被 AUTO_INCREMENT
修饰的字段的值是连续递增的。
InnoDB 存储引擎提供了一种轻量级的锁来实现自增。一样也是在插入数据的时候,会为被 AUTO_INCREMENT
修饰的字段加上轻量级锁,然后给该字段赋值一个自增的值,就把这个轻量级锁释放了,而不需要等待整个插入语句执行完后才释放锁。
行级锁
//对读取的记录加共享锁
select ... lock in share mode;
//对读取的记录加独占锁
select ... for update;
共享锁(S锁)满足读读共享,读写共享。独占锁(X锁)满足写写互斥,读写互斥。
Record Lock
Record Lock 称为记录锁,锁住的是一条记录。而且记录锁是有 S 锁和 X 锁之分的:
-
当一个事务对一条记录加了 S 型记录锁后,其他事务也可以继续对该记录加 S 型记录锁(S 型与 S 锁兼容),但是不可以对该记录加 X 型记录锁(S 型与 X 锁不兼容);
-
当一个事务对一条记录加了 X 型记录锁后,其他事务既不可以对该记录加 S 型记录锁(S 型与 X 锁不兼容),也不可以对该记录加 X 型记录锁(X 型与 X 锁不兼容)。
Gap Lock
间隙锁虽然存在 X 型间隙锁和 S 型间隙锁,但是并没有什么区别,间隙锁之间是兼容的,即两个事务可以同时持有包含共同间隙范围的间隙锁,并不存在互斥关系,因为间隙锁的目的是防止插入幻影记录而提出的
Next-Key Lock
next-key lock 是包含间隙锁+记录锁的,如果一个事务获取了 X 型的 next-key lock,那么另外一个事务在获取相同范围的 X 型的 next-key lock 时,是会被阻塞的
插入意向锁
一个事务在插入一条记录的时候,需要判断插入位置是否已被其他事务加了间隙锁(next-key lock 也包含间隙锁)。
如果有的话,插入操作就会发生阻塞,直到拥有间隙锁的那个事务提交为止(释放间隙锁的时刻),在此期间会生成一个插入意向锁,表明有事务想在某个区间插入新记录,但是现在处于等待状态。