MySQL全局锁会申请一个全局的读锁,对整个库加锁。
全局锁的一般使用场景是:全局逻辑备份。全局锁的实现方式有两种:
//第一种方法 Flush tables with read lock(FTWRL) //第二种方法 set global readonly=true
当数据库处于全局锁的状态时,其他线程的一下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(建表、索引变更、修改表结构等)和更新类事务的提交语句。
释放全局锁
unlock tables;
来个示例吧~
创建数据库 `test`
CREATE TABLE `test` ( `name` varchar(32) NOT NULL DEFAULT '', `bid` int(10) unsigned NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测试';
插入数据
insert into test values('A', 1), ('B',2),('C',3);
查看表数据
> select * from test; +------+-----+ | name | bid | +------+-----+ | A | 1 | | B | 2 | | C | 3 | +------+-----+
加锁
flush tables with read lock;
新增数据
insert into test values('D', 4);
执行 insert 操作后,直接返回错误结果:
ERROR 1223 (HY000): Can't execute the query because you have a conflicting read lock
执行查询操作,可以正常返回结果:
> select * from test; #返回结果: +------+-----+ | name | bid | +------+-----+ | A | 1 | | B | 2 | | C | 3 | +------+-----+vv
可以看到,当我们加上全局锁的时候,数据及表更新操作都没办法执行,但表查询不受影响。这样会给我们的业务造成很大的影响(无法修改数据),索性 Innodb 引擎的可重复读隔离级别可以让我们不阻塞数据变更的同时导出数据。
官方自带的逻辑备份工具是 mysqldump。当 mysqldump 使用参数–single-transaction 的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。而由于 MVCC 的支持,这个过程中数据是可以正常更新的。
你一定在疑惑,有了这个功能,为什么还需要 FTWRL 呢?一致性读是好,但前提是引擎要支持这个隔离级别。比如,对于 MyISAM 这种不支持事务的引擎,如果备份过程中有更新,总是只能取到最新的数据,那么就破坏了备份的一致性。这时,我们就需要使用 FTWRL 命令了。single-transaction 方法只适用于所有的表使用事务引擎的库。如果有的表使用了不支持事务的引擎,那么备份就只能通过 FTWRL 方法。这往往是 DBA 要求业务开发人员使用 InnoDB 替代 MyISAM 的原因之一。
用 FTWRL 而不用 set global readonly = true
- 在有些系统中,readonly 的值会被用来做其他逻辑,比如用来判断一个库是主库还是备库。因此,修改 global 变量的方式影响面更大,我不建议你使用。
- 在异常处理机制上有差异。如果执行 FTWRL 命令之后由于客户端发生异常断开,那么 MySQL 会自动释放这个全局锁,整个库回到可以正常更新的状态。而将整个库设置为 readonly 之后,如果客户端发生异常,则数据库就会一直保持 readonly 状态,这样会导致整个库长时间处于不可写状态,风险较高。