全局锁
全局锁就是对数据库加锁,加锁后DML,DDL和更新类事务的提交都将被阻塞。 典型应用场景为数据备份,对数据库加锁后,保证数据一致性。
-- 语法
flush tables with read lock; -- 加锁 简称`FTWRL`
unlock tables; -- 解锁
–-single-transaction:此选项会将隔离级别设置为:REPEATABLE READ。并且随后再执行一条START TRANSACTION语句,让整个数据在dump过程中保证数据的一致性。 当mysqldump使用参数–-single-transaction的时候,导数据之前就会启动一个事务,来确保拿到一致性视图(快照读)。由于MVCC的支持,这个过程中数据是可以正常更新的。注意:
–-single-transaction方法只适用于innodb引擎。因为一致性读不能隔离
DDL,在dump时如果执行了DDL则会导致数据不一致。
还有一种加全局锁的方式为
set global readonly = true,但不建议使用
- 在有些系统中,
readonly的值会被用来做其他逻辑,比如用来判断一个库是主库还是备库。因此,修改 global 变量的方式影响面更大,不建议使用。- 如果执行
FTWRL命令之后由于客户端发生异常断开,那么MySQL会自动释放这个全局锁,整个库回到可以正常更新的状态。而将整个库设置为readonly之后,如果客户端发生异常,则数据库就会一直保持readonly状态,这样会导致整个库长时间处于不可写状态,风险较高。
表级锁
表级锁顾名思义锁住整张表,锁粒度大,锁冲突概率高,并发低。 在常用存储引擎(MyISAM,INNODB等)都可以使用。
表锁
-- 语法
lock tables ${db} read; -- 读锁
lock tables ${db} write; -- 写锁
unlock tables; -- 解锁 会话断开连接也会自动解锁
读锁不会阻塞其他会话读,会阻塞写。(共享)
写锁只有自己能读写,其他会话不能读写。(排他)
元数据锁(meta data lock,MDL)
MDL用于维护表元数据(表结构)的一致性,在表有活动事务时,不能修改表结构。 其加锁解锁由系统自动控制,无需显示使用。
在MySQL5.5中引入了MDL,在对表CRUD时加MDL共享读写锁,在修改表结构时加MDL排它锁。
| SQL | 锁类型 | 说明 |
|---|---|---|
| select,select ... lock in share mode | MDL共享读锁(SHARED_READ) | MDL共享读锁和MDL共享写锁兼容,与MDL排它锁互斥 |
| insert,update,delete,select ... for update | MDL共享写锁(SHARED_WRITE) | MDL共享读锁和MDL共享写锁兼容,与MDL排它锁互斥 |
| alter table ... | MDL排它锁(EXCLUSIVE) | MDL排它锁与其它MDL锁都互斥 |
事务提交后自动解锁。
-- 查询元数据锁
SELECT
object_type,
object_schema,
object_name,
lock_type,
lock_duration
FROM
PERFORMANCE_SCHEMA.metadata_locks;
意向锁
意向锁用来优化加了行锁后,再申请表锁时效率低下的问题。 如一行数据有了行锁后,再加表锁,行锁肯定是跟表锁冲突的,所以常规是需要遍历数据才能知道有没有行锁,这样效率很低,从而使用意向锁来优化。
意向共享锁(IS):由语句 select ... lock in share mode添加。其与表读锁兼容,与表写锁互斥
意向排它锁(IX):由语句insert, update, delete, select ... for update添加。其与表读写锁都互斥
意向锁之间不互斥
-- 此语句可以查询意向锁和行锁
SELECT
object_schema,
object_name,
index_name,
lock_type,
lock_mode,
lock_data
FROM
PERFORMANCE_SCHEMA.data_locks;
行级锁
行级锁顾名思义锁住表的一行数据,锁粒度小,锁冲突概率低,并发高。在INNODB存储引擎使用。
行级锁是对索引上的索引项加锁实现的,而不是对行数据加的锁。
行锁(Record Lock)
行锁锁定单行记录,防止其它事务进行update和delete,在RC,RR级别支持。
针对索引字段匹配到的行数据是行锁。非索引字段进行加共享锁时,会变为表读锁;加排它锁时,会变为表写锁。
共享锁(S):允许获取当行共享锁的事务读,也允许其它事务获取当行共享锁,排斥其它事务获取当行的排它锁。
排它锁(X):允许获取当行排它锁的事务读写,排斥其它事务获取当行的共享锁和排它锁。
| SQL | 锁类型 |
|---|---|
| INSERT,UPDATE,DELETE | 排它锁 |
| SELECT | 无锁 |
| SELECT ... LOCK IN SHARE MODE | 共享锁 |
| SELECT ... FOR UPDATE | 排它锁 |
间隙锁(Gap Lock)/ 临键锁(Next-Key Lock)
间隙锁防止其它事务在这个间隙insert,产生幻读。临键锁是行锁和间隙锁的组合。在RR隔离级别支持。
-
针对唯一索引获取锁查询
-
等值查询
- 存在的数据,只会锁当前行(行锁)。
- 不存在的数据会给符合条件左边不存在的记录加间隙锁,无法在此间隙插入数据。
-
范围查询
- 会给符合条件的存在的数据加锁(不能修改删除,行锁)及符合条件的不存在的数据区间添加间隙锁,无法在此间隙插入数据。
-
-
针对普通索引获取锁查询
-
等值查询
- 存在的数据,会给符合条件的数据加锁(不能修改删除,行锁)及无法插入相同普通索引的值,可以插入不同索引的值。
- 不存在的数据,类似表锁,无法插入数据。
-
范围查询
- 存在的数据,会给符合条件的数据加锁(不能修改删除,行锁)及无法插入所有符合条件数据相同普通索引的值,可以插入不同索引的值。
- 不存在的数据,类似表锁,无法插入数据。
-
总结
MySQL中的锁基本都是分为共享锁和排它锁,记住多个共享锁可以兼容,排它锁与其它锁都不兼容就可以。