全局锁、表锁
作者:互联网
全局锁
全局锁的典型使用场景是,做全库逻辑备份
历史做法:flush table with read lock;
确保不会有其他线程对数据库做更新,然后对整个库做备份。
mysql> flush table with read lock;
Query OK, 0 rows affected (0.10 sec)
mysql> select * from t;
+----+------+------+
| id | c | d |
+----+------+------+
| 0 | 0 | 0 |
| 5 | 5 | 5 |
| 10 | 10 | 55 |
| 15 | 15 | 15 |
| 20 | 20 | 20 |
| 25 | 25 | 25 |
+----+------+------+
6 rows in set (0.01 sec)
mysql> update d set d = 99 where id = 0;
ERROR 1223 (HY000): Can't execute the query because you have a conflicting read lock
缺陷:
- 备份期间都不能执行更新,业务基本上就得停摆;
- 主从同步导致数据不一致
官方自带的逻辑备份工具是 mysqldump,mysqldump 使用参数–single-transaction 的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。而由于 MVCC 的支持,这个过程中数据是可以正常更新的。
能够支持事务隔离的,就可以通过事务隔离的手段来做到,有的引擎不支持(如:MyISAM不支持),需要通过FTWRL来给全局上锁
为什么不用set global readonly=true?
- readonly 的值会可能会被用来做其他逻辑,如:主备库判断
- 异常机制差异(客户端发生异常断开,FTWRL会释放全局锁,整个库回到可以正常更新的状态,readonly 不会)
表级锁
表锁
语法:lock tables … read/write
解除:unlock tables
写锁(排他锁):自己能写
读锁(共享锁):都能读,不能写
对于 InnoDB 这种支持行锁的引擎,一般不使用 lock tables 命令来控制并发,毕竟锁住整个表的影响面还是太大。
MDL(metadata lock)
MDL(MySQL 5.5 版本中引入) 的作用是,保证读写的正确性,MDL 不需要显式使用,在访问一个表的时候会被自动加上。
- 读锁:对一个表做增删改查操作的时
- 写锁:当要对表做结构变更操作的时
读锁与读锁止键不互斥,写锁与写锁,读锁与写锁之间互斥,用来保证变更表结构操作的安全性
注意安全性:
session A 先启动,这时候会对表 t 加一个 MDL 读锁。
session B 需要的也是 MDL 读锁,因此可以正常执行。
session C 会被 blocked,是因为 session A 的 MDL 读锁还没有释放。session D 也会被 blocked。
导致问题:如果查询语句频繁,且客户端有重试机制会打爆Mysql
结论:事务中的 MDL 锁,在语句执行开始时申请,但是语句结束后并不会马上释放,而会等到整个事务提交后再释放
如何安全地给小表加字段?
- information_schema 库的 innodb_trx 表中如果有长事务,暂停 DDL,或者 kill 掉这个长事务。
- alter table 语句里面设定等待时间。(如果在这个指定的等待时间里面能够拿到 MDL 写锁最好,拿不到也不要阻塞后面的业务语句,先放弃。之后开发人员或者 DBA 再通过重试命令重复这个过程)
思想:防止死锁,加入超时时间机制
MariaDB 已经合并了 AliSQL 的这个功能,所以这两个开源分支目前都支持 DDL NOWAIT/WAIT n 这个语法
ALTER TABLE tbl_name NOWAIT add column ...
ALTER TABLE tbl_name WAIT N add column ...
MySQL 8.0.1在select语法中给出了NOWAIT特性(官方博客),也就是我们可以在查询时如果需要等待行锁,则立即退出报错。这种特性其实也可以用在MDL锁,这样我们如果在进行DDL语句时,通过NOWAIT检测一下是否有相关元数据锁等待,如果有则立即退出,这样运维人员即可及时判断出能否进行ddl操作,而不至于在执行ddl时,造成大量业务中断。
标签:语句,事务,MDL,lock,读锁,session,全局,表锁 来源: https://blog.csdn.net/qq_42239520/article/details/122297431