Mysql学习笔记--全局锁与表锁

451 阅读4分钟

思考

全局锁

1.全局锁 Flush tables with read lock (FTWRL) Unlock tables解锁

2.全局锁的典型使用场景是,做全库逻辑备份。也就是把整库每个表都 select 出来存成文本。比如 MyISAM 这种不支持一致性读的存储引擎做全库备份时需要使用全局锁,像 InnoDB 引擎做全库备份时不需要使用全局锁。

3.FTWRL确保其他线程DML DDL不会对表有影响

4.加锁的好处:保证视图逻辑一致与mysqldump事务--single-transaction(导数据之前启动一个事务来保证一致性视图)

使用 --single-transaction弊端:只支持事务引擎,mysql其他引擎无法使用

5.全局锁与set global readonly=true对比

  • 有些系统 set global readonly=true 这个命令经常用在判断一个库是主库还是从库
  • 当系统发生异常的时候,FTWRL会自动释放这个全局锁,但是只读状态会一直保持这个状态,导致数据库不可写,风险系数高。

表锁

1.表级锁分为两种:表锁和元数据锁(MDL)

举个例子, 如果在某个线程 A 中执行 lock tables t1 read, t2 write; 这个语句,则其他线程写 t1、读写 t2 的语句都会被阻塞。同时,线程 A 在执行 unlock tables 之前,也只能执行读 t1、读写 t2 的操作。连写 t1 都不允许,自然也不能访问其他表。

2.MDL锁不需要显示使用,访问一个表会自动加上

MDL 的作用是,保证读写的正确性。你可以想象一下,如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个表结构做变更,删了一列,那么查询线程拿到的结果跟表结构对不上,肯定是不行的。

3.DML加读锁 DDL加写锁,读锁之间不互斥,多个线程可以对同一张表进行增删改查,读写锁之间,写锁之间互斥

实践

全局锁

flush tables with read lock

[SQL]flush tables with read lock 受影响的行: 0 时间: 0.010s

此时对数据库执行DML操作,数据库一直处在阻塞状态。

insert into d(`id`) VALUES(1)

[SQL]insert into d(`id`) VALUES(1)

此时执行解锁操作

unlock tables

[SQL]unlock TABLES 受影响的行: 0 时间: 0.000s 

再执行插入操作,数据库已经可以插入数据了

insert into d(`id`) VALUES(1)

表锁

开启一个事务执行查询语句

begin;
SELECT * from article

结果:查询到数据

继续查询这张表

SELECT * from article

结果:查询到数据

增加字段操作

alter table `article`  add COLUMN b INT;

结果:阻塞

继续查询操作

select * from `article` ;

结果:阻塞

alter table `article` add COLUMN b INT;

生成MDL写锁,第一次查询的读锁还没有释放,读写锁之间互斥造成阻塞

问题

不过令一个实验让我有点费解

navicat新建查询进行锁表,再次新建查询进行解锁失败。

答:??

如何避免这种阻塞情况?

答:1.kill掉这个长事务

       2.设置超时时间如果在等待时间能拿到写锁最好,拿不到就等一会让DBA再次执行语句

MariaDB 已经合并了 AliSQL 的这个功能,所以这两个开源分支目前都支持 DDL NOWAIT/WAIT n 这个语法。

ALTER TABLE tbl_name NOWAIT add column ...
ALTER TABLE tbl_name WAIT N add column ... 

结论

1.全局锁主要用在逻辑备份过程,对于全部InnoDB引擎的库最好使用single-transaction 参数

2.表锁一般是在数据库引擎不支持行锁的时候才会被用到的。如果你发现你的应用程序里有 lock tables 这样的语句,你需要追查一下,比较可能的情况是:要么是你的系统现在还在用 MyISAM 这类不支持事务的引擎,那要安排升级换引擎;要么是你的引擎升级了,但是代码还没升级。我见过这样的情况,最后业务开发就是把 lock tables 和 unlock tables 改成 begin 和 commit,问题就解决了。

3.MDL 会直到事务提交才释放,在做表结构变更的时候,你一定要小心不要导致锁住线上查询和更新。

摘要内容来源:极客时间Mysql45讲--全局锁和表锁:给字段怎么有这么多障碍?