1. 全局锁
全局锁是一种对整个数据库进行锁定的操作,通常用于确保在备份期间数据的一致性。全局锁在操作期间会阻止所有写操作,因此会导致系统处于只读状态。
特点与使用
- 常用于备份操作:在备份期间,通过加全局读锁防止数据的写入,确保备份期间数据的一致性。
- 限制:
- 在主库上加全局锁时,数据库不能进行写操作,备份期间会导致业务停滞。
- 在从库上加全局锁时,会影响从主库同步二进制日志(binlog),可能导致主从延迟。
命令示例
- 使用
FLUSH TABLES WITH READ LOCK;
来加全局读锁,将数据库置于只读状态。 - 使用
UNLOCK TABLES;
来解除全局锁,恢复数据库正常读写。
备份命令示例
在备份时可以使用 mysqldump
命令,加上 --single-transaction
参数来实现一致性备份:
mysqldump --single-transaction -uroot 数据库名 > 备份文件.sql
使用 --single-transaction
参数可以在InnoDB存储引擎中不加全局锁进行一致性备份。
2. 表级锁
表级锁是对单张表加锁的机制,每次锁定整张表,锁定粒度较大,冲突概率高,但实现简单,开销较小。适用于MyISAM、InnoDB、BDB等存储引擎。
表级锁的类型
-
表锁(Table Lock)
- 共享读锁(Read Lock):多个事务可以同时获取共享读锁,允许并发读取数据,但禁止写入操作。
- 独占写锁(Write Lock):获取写锁的事务独占表的操作权限,禁止其他事务读取或写入,保证修改数据的一致性。
语法示例:
LOCK TABLES 表名 READ; -- 共享读锁 LOCK TABLES 表名 WRITE; -- 独占写锁 UNLOCK TABLES; -- 解除锁
-
元数据锁(Meta Data Lock, MDL)
- 自动加锁机制:MySQL 5.5后引入,无需显式使用,主要用于保护表的元数据一致性。
- 功能:防止并发的DML和DDL冲突。当一个事务对表结构进行修改(如
ALTER TABLE
),会阻止其他事务对表执行数据修改操作,直到DDL操作完成。 - 锁类型:包括
SHARED_READ
、SHARED_WRITE
、EXCLUSIVE
等类型,分别用于读取、写入、结构变更等不同的操作。
查询元数据锁状态:
SELECT object_type, object_schema, object_name, lock_type, lock_duration FROM performance_schema.metadata_locks;
-
意向锁(Intention Lock)
- 意向锁用于表明事务对表的操作意图,减少表锁和行锁的冲突,提高并发效率。
- 类型:
- 意向共享锁(IS):用于声明事务将获取表中某些记录的共享锁,一般用于
SELECT ... LOCK IN SHARE MODE
。 - 意向排他锁(IX):用于声明事务将获取表中某些记录的排他锁,一般用于
INSERT
、UPDATE
、DELETE
等写操作。
- 意向共享锁(IS):用于声明事务将获取表中某些记录的共享锁,一般用于
- 特性:意向锁之间不会互斥,可以共存,允许多个事务在同一张表上进行不同的操作。
查询意向锁状态:
SELECT object_schema, object_name, index_name, lock_type, lock_mode, lock_data FROM performance_schema.data_locks;
3. 行级锁
行级锁是锁机制中粒度最小的一种锁,仅锁定特定的行数据,锁冲突概率低,并发度高,主要用于InnoDB存储引擎。
行级锁的类型
- 共享锁(S锁):用于读取操作。允许多个事务同时对某行数据加共享锁,防止其他事务对该行数据加排他锁。
- 排他锁(X锁):用于写操作。获取排他锁的事务可以更新该行数据,阻止其他事务对该行数据加共享锁和排他锁,保证写操作的独占性。
行级锁的SQL操作
- INSERT、UPDATE、DELETE:自动加排他锁,确保在写操作期间其他事务不能操作相同的数据行。
- SELECT ... LOCK IN SHARE MODE:手动加共享锁,确保其他事务不能加排他锁,防止数据被修改。
- SELECT ... FOR UPDATE:手动加排他锁,确保在读取后进行更新时其他事务无法操作相同的数据行。
4. 间隙锁和Next-Key锁
InnoDB使用Next-Key锁(行锁+间隙锁)来防止幻读问题,在REPEATABLE READ
隔离级别下自动生效。
Next-Key锁和间隙锁的机制
- 唯一索引等值查询:当查询的是一个唯一索引项且存在匹配记录,Next-Key锁优化为行锁,只锁定该记录。
- 普通索引等值查询:查询匹配的记录范围,锁定最后一个满足条件的记录及其前后的间隙。
- 范围查询:对满足条件的记录加锁,并锁定范围内的间隙。
间隙锁的作用
间隙锁(Gap Lock)用于防止其他事务在锁定范围内插入数据,以避免幻读。间隙锁之间不互斥,可以共存,但对插入操作有限制。
注意:间隙锁的目的是防止新数据插入,不影响已存在数据的读取和更新操作。
5. 锁机制的总结和对比
锁类型 | 作用范围 | 常用场景 | 优缺点 |
---|---|---|---|
全局锁 | 整个数据库 | 备份操作 | 粒度最大,阻塞性强,会影响业务 |
表级锁 | 整张表 | 并发低的操作场景 | 实现简单,开销小,但冲突概率高 |
元数据锁 | 表元数据 | DDL和DML操作保护 | 自动加锁,防止结构变更时数据读写冲突 |
意向锁 | 表或行 | 表示操作意图 | 与行级锁配合使用,提高并发性 |
行级锁 | 单行数据 | 高并发场景 | 粒度最小,并发性高,适用于InnoDB |
Next-Key锁 | 行和间隙 | 防止幻读 | 防止幻读的同时保持行锁的精细控制,适用于可重复读隔离级别 |
间隙锁 | 索引间隙 | 避免新数据插入 | 防止幻读,允许多个事务加同一间隙锁,但影响插入操作 |
6. 使用锁的优化
- 使用索引优化查询:行级锁依赖索引进行加锁,使用索引可以减少锁的范围,避免表锁或行锁的升级。
- 合理选择隔离级别:
REPEATABLE READ
隔离级别适合大多数场景,避免幻读问题。但在高并发场景中,可以根据业务需求适当放宽隔离级别。 - 避免大事务操作:长时间持有锁会影响并发性能,应尽量减少事务的执行时间,将长事务拆分为小事务。
- 使用意向锁进行声明:通过意向锁声明操作意图,减少锁冲突,提升事务的并发处理能力。
- 监控锁状态:使用
performance_schema
中的相关查询来监控数据库的锁状态,及时识别和解决锁冲突。
锁状态查询示例
-
查询元数据锁:
SELECT object_type, object_schema, object_name, lock_type, lock_duration FROM performance_schema.metadata_locks;
-
查询意向锁和行锁:
SELECT object_schema, object_name, index_name, lock_type, lock_mode, lock_data FROM performance_schema.data_locks;
通过对锁机制的合理使用,可以在高并发的数据库环境中提高数据一致性、避免冲突和数据竞争问题,从而实现高效、稳定的数据库性能。