MySQL 45 讲学习笔记 ☞ 06 全局锁和表锁:给表加个字段怎么有这么多阻碍? @ FnEsc | 2021-07-13T18:02:53+08:00 | 3 分钟阅读

根据加锁的范围,MySQL 里面的锁大致可以分成全局锁、表级锁和行锁三类。

全局锁

全局锁是对整个数据库实例加锁。MySQL 的命令是 Flush tables with read lock (FTWRL) (需要引擎支持一致性读这个隔离级别),之后整个库处于只读状态。其典型使用场景是:做全库逻辑备份。

加锁备份:

官方自带的逻辑备份工具是 mysqldump。当 mysqldump 使用参数 –single-transaction 的时候,导数据之前就会启动一个事务(需要使用事务引擎),来确保拿到一致性视图。

其实还有一个方式可以实现全库只读:set global readonly=true 。但是:

  1. 该值有时候还会用来做其他逻辑,比如判断主备库,影响面更大。
  2. 在异常处理机制上:FTWRL 后由客户端异常断开,那么 MySQL 会自动释放这个全局锁,回到可以正常更新的状态;如果是修改 readonly 后由客户端异常断开,则数据库就会一直保持 readonly 状态,这样会导致整个库长时间处于不可写状态,风险较高。

业务的更新

  • 增删改数据(DML)
  • 修改表结构的操作(DDL)

表级锁

MySQL 里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)。

表锁

表锁的语法是 lock tables … read/write (unlock tables 主动释放锁)。表锁一般是在数据库引擎不支持行锁的时候才会被用到的。

需要注意,lock tables 语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象。比如,线程 A lock tables t1 read, t2 write;,那么 A 在执行 unlock tables 之前,只能执行读 t1 & 读写 t2 的操作,不能写 t1 也不能访问其他表。

在还没有出现更细粒度的锁的时候,表锁是最常用的处理并发的方式。而对于 InnoDB 这种支持行锁的引擎,一般不使用 lock tables 命令来控制并发,毕竟锁住整个表的影响面还是太大。

元数据锁 MDL

MDL 不需要显式使用,在访问一个表的时候会被自动加上。MDL 的作用是,保证读写的正确性。

注意元数据锁也可能会引起大影响,这里举例:

MDL 事务阻塞影响

这里的顺序可以这样梳理:

  1. Seesion A 启动,对表 t 加 MDL 读锁。可见,MDL 在语句执行开始时申请,但是语句结束后并不会马上释放,而会等到整个事务提交后再释放。
  2. Session B 需要的也是 MDL 读锁,因此可以正常执行。
  3. Session C 会被 blocked,因为 Session A 的 MDL 读锁还没有释放,只能被阻塞。
  4. Session D 申请 MDL 读锁的请求也会被 Session C 阻塞。

假如表查询频繁,且客户端有重试机制(超时后发起新 Session 再请求),这个库的线程很快就会爆满。

问:如何给热点表加字段?

答:比较理想的机制是,在 alter table 语句里面设定等待时间,如果在这个指定的等待时间里面能够拿到 MDL 写锁最好,拿不到也不要阻塞后面的业务语句,先放弃。之后开发人员或者 DBA 再通过重试命令重复这个过程。

© 2021 FnEsc Hugo Site

Powered by Hugo with theme Dream.

avatar

FnEsc 的博客一边担心未来,一边浪费现在。

关于我

FnEsc 的 💜 博客

自从 2021.07 开始搭建该 hugo 博客,作为记录一些生活/技术上的小笔记

2020届应届生,毕业与佛山科学技术学院计算机科学与技术专业

目前职业是 全栈开发程序🐶 打杂工具人

作为传统行业外企电商的 965,使我并没有很勤奋卷

不想那么相关工作为 SAP Fiori 应用开发和维护。

目前主要的技术栈是:

  • Python Web 端架构
  • Django / Odoo 开发

接下来可能想学习的方向是:

  • Python 进阶(流畅的 python)
  • MySQL 知识巩固(MySQL 实战 45 讲)
  • Go 开始学习(Go 语言核心 36 讲)
  • 其他架构/算法尝试学习
社交链接