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


因为在可重复读的隔离级别下 , 即使其他事务更新了表的数据 , 也不会影响备份数据库时的 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;需要注意的是 , 表锁除了会限制别的线程的读写外 , 也会限制本线程接下来的读写操作 。
也就是说如果本线程对学生表加了「共享表锁」 , 那么本线程接下来如果要对学生表执行写操作的语句 , 是会被阻塞的 , 当然其他线程对学生表进行写操作时也会被阻塞 , 直到锁被释放 。
要释放表锁 , 可以使用下面这条命令 , 会释放当前会话的所有表锁:
unlock tables另外 , 当会话退出后 , 也会释放所有表锁 。
不过尽量避免在使用 InnoDB 引擎的表使用表锁 , 因为表锁的颗粒度太大 , 会影响并发性能 , InnoDB 牛逼的地方在于实现了颗粒度更细的行级锁 。
元数据锁再来说说元数据锁(MDL) 。
我们不需要显示的使用 MDL , 因为当我们对数据库表进行操作时 , 会自动给这个表加上 MDL:
  • 对一张表进行 CRUD 操作时 , 加的是 MDL 读锁;
  • 对一张表做结构变更操作的时候 , 加的是 MDL 写锁;
MDL 是为了保证当用户对表执行 CRUD 操作时 , 防止其他线程对这个表结构做了变更 。
当有线程在执行 select 语句( 加 MDL 读锁)的期间 , 如果有其他线程要更改该表的结构( 申请 MDL 写锁) , 那么将会被阻塞 , 直到执行完 select 语句( 释放 MDL 读锁) 。
反之 , 当有线程对表结构进行变更( 加 MDL 写锁)的期间 , 如果有其他线程执行了 CRUD 操作( 申请 MDL 读锁) , 那么就会被阻塞 , 直到表结构变更完成( 释放 MDL 写锁) 。
MDL 不需要显示调用 , 那它是在什么时候释放的?
MDL 是在事务提交后才会释放 , 这意味着事务执行期间 , MDL 是一直持有的 。
那如果数据库有一个长事务(所谓的长事务 , 就是开启了事务 , 但是一直还没提交) , 那在对表结构做变更操作的时候 , 可能会发生意想不到的事情 , 比如下面这个顺序的场景:
  1. 首先 , 线程 A 先启用了事务(但是一直不提交) , 然后执行一条 select 语句 , 此时就先对该表加上 MDL 读锁;

    经验总结扩展阅读