MySQL 全局锁、表级锁、行级锁,你搞清楚了吗?

大家好,我是小林 。
最近重新补充了《MySQL 有哪些锁》文章内容:

  • 增加记录锁、间隙锁、net-key 锁
  • 增加插入意向锁
  • 增加自增锁为 innodb_autoinc_lock_mode = 2 模式时,为什么主从环境会有不安全问题的说明
所以,现在内容还是比较全面的,基本把 MySQL 用到的锁都说了一遍,大家可以在复习复习 。
这次 , 来说说 MySQL 的锁,主要是 Q&A 的形式,看起来会比较轻松 。
不多 BB 了 , 发车!
在 MySQL 里,根据加锁的范围 , 可以分为全局锁、表级锁和行锁三类 。
MySQL 全局锁、表级锁、行级锁,你搞清楚了吗?

文章插图
全局锁
全局锁是怎么用的?
要使用全局锁 , 则要执行这条命:
flush tables with read lock执行后 , 整个数据库就处于只读状态了,这时其他线程执行以下操作,都会被阻塞:
  • 对数据的增删改操作,比如 insert、delete、update等语句;
  • 对表结构的更改操作,比如 alter table、drop table 等语句 。
如果要释放全局锁 , 则要执行这条命令:
unlock tables当然,当会话断开了,全局锁会被自动释放 。
全局锁应用场景是什么?
全局锁主要应用于做全库逻辑备份,这样在备份数据库期间,不会因为数据或表结构的更新 , 而出现备份文件的数据与预期的不一样 。
举个例子大家就知道了 。
在全库逻辑备份期间,假设不加全局锁的场景 , 看看会出现什么意外的情况 。
如果在全库逻辑备份期间,有用户购买了一件商品,一般购买商品的业务逻辑是会涉及到多张数据库表的更新 , 比如在用户表更新该用户的余额 , 然后在商品表更新被购买的商品的库存 。
那么,有可能出现这样的顺序:
  1. 先备份了用户表的数据;
  2. 然后有用户发起了购买商品的操作;
  3. 接着再备份商品表的数据 。
也就是在备份用户表和商品表之间 , 有用户购买了商品 。
这种情况下,备份的结果是用户表中该用户的余额并没有扣除,反而商品表中该商品的库存被减少了,如果后面用这个备份文件恢复数据库数据的话,用户钱没少 , 而库存少了,等于用户白嫖了一件商品 。
所以,在全库逻辑备份期间,加上全局锁,就不会出现上面这种情况了 。
加全局锁又会带来什么缺点呢?
加上全局锁,意味着整个数据库都是只读状态 。
那么如果数据库里有很多数据,备份就会花费很多的时间,关键是备份期间 , 业务只能读数据 , 而不能更新数据,这样会造成业务停滞 。
既然备份数据库数据的时候 , 使用全局锁会影响业务,那有什么其他方式可以避免?
有的 , 如果数据库的引擎支持的事务支持可重复读的隔离级别,那么在备份数据库之前先开启事务,会先创建 Read View,然后整个事务执行期间都在用这个 Read View,而且由于 MVCC 的支持 , 备份期间业务依然可以对数据进行更新操作 。
因为在可重复读的隔离级别下,即使其他事务更新了表的数据 , 也不会影响备份数据库时的 Read View,这就是事务四大特性中的隔离性,这样备份期间备份的数据一直是在开启事务时的数据 。
备份数据库的工具是 mysqldump,在使用 mysqldump 时加上 –single-transaction 参数的时候 , 就会在备份数据库之前先开启事务 。这种方法只适用于支持「可重复读隔离级别的事务」的存储引擎 。
InnoDB 存储引擎默认的事务隔离级别正是可重复读,因此可以采用这种方式来备份数据库 。
但是,对于 MyISAM 这种不支持事务的引擎,在备份数据库时就要使用全局锁的方法 。
表级锁
MySQL 表级锁有哪些?具体怎么用的 。
MySQL 里面表级别的锁有这几种:
  • 表锁;
  • 元数据锁(MDL);
  • 意向锁;
  • AUTO-INC 锁;
表锁先来说说表锁 。
如果我们想对学生表(t_student)加表锁 , 可以使用下面的命令:
//表级别的共享锁 , 也就是读锁;lock tables t_student read;//表级别的独占锁 , 也就是写锁;lock tables t_stuent write;

推荐阅读