前言
大家都知道锁是用来保护并发访问的资源的,Mysql中根据锁的粒度分为了全局锁、表锁以及行锁。今天这篇文章我们一起一起探讨下Mysql中的这三种锁
全局锁
全局锁是Mysql中粒度最粗的锁,它的作用是给数据库实例进行上锁。
一旦该数据库实例被上了全局锁,那么该实例就处于了只读状态,像一些DDL(create/alter table等)语句更新语句(update/insert)就会被阻塞。
你可以使用以下命令给一个数据库实例上全局锁
Flush tables with read lock
解锁
UNLOCK TABLES
使用场景
全库逻辑备份
带来的问题
- 在主库上备份时:数据无法更新和写入,对业务影响太大
- 在从库上备份时:从库无法执行主库同步的binlog,从而导致主从延迟(备份时间越长,延迟越大)
替代方案
一致性视图
mysql中我们获取一致性视图的方法之一:在「可重复读」的隔离级别中开启一个事务。注意这里的前提是你的存储引擎必须支持事务,像MyISAM这种就是不支持事务存储引擎,自然也无法利用一致性视图来代替全局锁来进行全库备份。所以我们的业务场景中一般建议你使用InnoDB存储引擎。
mysql提供了mysqldump备份工具,如果你使用的是InnoDB存储引擎的话。那么你可以使用-single-transaction参数来确保备份的时候使用一致性视图,具体命令如下:
mysqldump -single-transaction -u username -p dbname [tbname ...]> xxx.sql
set global readonly
和全局锁设置全库只读功能类似,mysql提供了set global readonly = true的命令来让全库进入只读状态。但它相比全局锁有以下弊端:
- set global readonly 有些场景中会被用来判断是否是主库还是备库。比如当该属性的true时,会认为当前库为备库
- 当持有全局锁的客户端发生异常断开时,那么mysql会释放该客户端持有的全局锁,让实例回到正常状态。而set global readonly中的客户端一旦发生异常,实例还是处于readonly状态。在运维人员没发现之前就会导致实例一直处于只读状态
表锁
Mysql中表锁分为两种
- Table lock
- MDL(Meta data lock 5.5之后引入)
我们今天只探讨Table lock
Table lock的语法是:
lock tables A,B,.... read/write
解锁:
unlock tables
lock table命令会限制当前线程和其他线程对表的操作,具体我们以以下示例来说明:
假设我们线程A中执行以下命令
lock tables A read, B write;
如上图所示:
当线程A持有Table A的读锁,Table的写锁时。线程B对TableA的读,对TableB的写就会被阻塞。同时线程A对TableC的读也将会被阻塞。