锁概述与全局锁
锁用来协调并发访问共享数据:按粒度分为全局锁 / 表级锁 / 行级锁,粒度越细并发度越高。全局锁用于全库逻辑备份,代价是整个实例只读。
一、概述
1.1 介绍
- 锁是计算机协调多个进程或线程并发访问某一资源的机制。
- 在数据库中,除传统的计算资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。
1.2 分类(按锁的粒度)
| 粒度 | 说明 |
|---|---|
| 全局锁 | 锁定数据库中的所有表 |
| 表级锁 | 每次操作锁住整张表 |
| 行级锁 | 每次操作锁住对应的行数据 |
粒度越大,加锁开销越小、冲突概率越高、并发度越低;粒度越小则相反。
二、全局锁
2.1 介绍
全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的:
- DML 的写语句;
- DDL 语句;
- 已经更新操作的事务提交语句
都将被阻塞。
典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。
为什么必须加锁:备份期间业务仍在写,逐表备份会拼出不一致的快照。
| 时间线 | 备份动作 | 同时发生的业务 |
|---|---|---|
| ① | 备份 tb_stock | |
| ② | 扣减库存 / 生成订单 | |
| ③ | 备份 tb_order | |
| ④ | 插入订单日志 | |
| ⑤ | 备份 tb_orderlog |
最终「备份数据」与业务实际状态不一致。加锁后备份期间只允许 DQL(读),DML / DDL 全部阻塞。
2.2 语法与演示
-- 加全局锁 → 整个实例只读
FLUSH TABLES WITH READ LOCK;
# 备份:加锁期间执行,只读操作不受影响(-p 后回车输入密码)
mysqldump -uroot -p itcast > itcast.sql
-- 释放锁
UNLOCK TABLES;
mysqldump -uroot -p会提示输入密码,也可以写成-p密码;会话断开时锁会自动释放。
2.3 特点与改进
加全局锁是一个比较重的操作,存在以下问题:
- 如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆;
- 如果在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志(binlog),会导致主从延迟。
在 InnoDB 引擎中,可以在备份时加上参数 --single-transaction 来完成不加锁的一致性数据备份:
# InnoDB 不加锁备份 → 备份期间不阻塞业务写入
mysqldump --single-transaction -uroot -p itcast > itcast.sql
依赖 InnoDB 的 MVCC 快照读;MyISAM 不支持事务,只能用全局锁。
速查
-- 加全局锁 → 实例只读(DML 写 / DDL / 事务提交均被阻塞)
FLUSH TABLES WITH READ LOCK;
-- 释放全局锁 → 会话断开也会自动释放
UNLOCK TABLES;
# 全库逻辑备份 → 加锁后执行,备份完再 UNLOCK TABLES
mysqldump -uroot -p itcast > itcast.sql
# InnoDB 不加锁的一致性备份 → 备份期间不阻塞写入
mysqldump --single-transaction -uroot -p itcast > itcast.sql
| 场景 | 关键点 |
|---|---|
| 全库逻辑备份 | 先 FLUSH TABLES WITH READ LOCK,备份完 UNLOCK TABLES |
| 备份期间不想停业务 | InnoDB 用 --single-transaction,靠 MVCC 拿一致性快照 |
| 加锁影响 | 实例只读:DML 写、DDL、事务提交都阻塞;从库备份还会导致主从延迟 |
相关
- 表级锁:表锁、元数据锁(MDL)、意向锁
- 行级锁:行锁、间隙锁、临键锁
- MySQL 体系结构与存储引擎:InnoDB 与 MyISAM 的差异
- 事务:事务提交与隔离级别