1. 锁类型
- 全局锁
- 表级锁
- 行锁
2. 全局锁
对整个数据库实例加锁,让整个库处于只读在状态(无法更新数据,创建表,修改表结构等)
Flush tables with read lock;
-- 做备份前用
-- 引擎不支持可重复读隔离级别时,只能这样
mysqldump --single-transaction
-- 仅仅用于支持可重复读的引擎.
-- 开启事务时,创建一个视图.保证备份过程中数据不会被修改.
2.1. 可能出现的问题
- 如果不使用
Flush tables with read lock;
,由于表备份有先后顺序,可能出现数据错误 - 不要使用
set global readonly=true
- readonly可能用于逻辑判断,如判断是否时从库
- 异常问题:
- 使用
Flush tables with read lock;
如果有异常,会自动释放. - readonly,客户端异常,不会释放.整个库将一直不可写.
- 使用
3. 表级锁
3.1. 表锁
lock tables t1 read,t2 write;
-- 当前线程只能读t1,读写t2,其他线程阻塞:不允许写t1,读写t2.
unlock tables t1,t2;
3.2. 元数据锁
访问表时自动加上:保证读写期间,表结构不变.
- 对表做增删改查,加MDL读锁
- 多个线程可以同时增删改查
- 对表做结构变更,加MDL写锁
- 只能有一个进行结构变更.
- session A加上MDL读锁
- session B 继续读
- Session C阻塞,因为session A的读锁还没有释放.没法加写锁
- session D阻塞,等待session C.
- 表现在不可读写
3.3. 如何正确的加字段
- 首先暂定长事务,再加锁
4. 问答
当备库用–single-transaction 做逻辑备份时,主库的binlog传过来一个DDL语句会怎么样?
Q1:SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; -- 设置可重复读
Q2:START TRANSACTION WITH CONSISTENT SNAPSHOT; -- 启动事务,并且使用WITH CONSISTENT SNAPSHOT获得一个一致性视图.
/* other tables */
Q3:SAVEPOINT sp; -- 保存点1
/* 时刻 1 */
Q4:show create table `t1`; -- 获取表结构
/* 时刻 2 */
Q5:SELECT * FROM `t1`; -- 获取数据
/* 时刻 3 */
Q6:ROLLBACK TO SAVEPOINT sp; -- 回滚到sp,释放t1的MDL锁.
/* 时刻 4 */
/* other tables */
根据DDL到来的时间不同可能的结果:
- Q4前到达,
- 现象:没有影响,备份的是表结构修改后的
- Q2到达,表结构修改过.Q5执行时,报错’Tables defination has changed,please retry transaction'
- 现象:mysqldump停止
- Q2和Q3之间到达,mysqldump占用t1表的读锁,binlog阻塞.
- 现象:主从延迟,直到Q6执行完
- Q4开始后,mysqldump释放MDL读锁
- 现象:无影响.备份的是修改前的结构.