根据加锁的范围,MySQL里面的锁大致可以分成全局锁、表级锁和行锁三类,本文先讨论前两种。

全局锁

全局锁是对整个数据库实例加锁,MySQL提供的加全局读锁的命令是Flush tables with read lock(下面简称FTWRL)。当需要让整个库处于只读状态时,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据的增删改、数据定义语句(表的建立与修改等)、更新类事务的提交语句。

全局锁的典型使用场景是全库逻辑备份,即把库中每个表都select出来存成文本。

让整个库都处于只读,有些弊端:

  • 若在主库上备份,那么在备份期间都不能执行更新,业务会停滞;

  • 若在从库上备份,那么备份期间从库不能执行主库同步过来的binlog,导致主从延迟。

那么既然备份加锁有这么多弊端,是否可以不加锁呢?

答案是不行的,考虑有用户余额表和订单表两张表,当用户发起一次购买,需要在用户余额表扣减余额,在订单表里增加一笔订单。若顺序是先备份用户余额表,然后用户购买,再备份订单表,不难发现会出现问题,顺序反之亦然。

官方自带的逻辑备份工具是mysqldump,当mysqldump使用参数single-transaction,在导数据之前就会启动一个事务,拿到一致性的视图。由于MVCC的支持,这个备份过程中数据可以正常更新。

那既然官方有这个工具,为什么需要FTWRL呢?答案是有些引擎并不支持可重复读的隔离级别,这时候必须使用FTWRL命令。因此,只有所有表都使用事务引擎的库才能使用single-transaction

还有一种想法是,为了让全库只读,使用set global readonly=true的方式。但还是建议使用FTWRL,原因如下:

  • 在有些系统中,readonly的值会被用作其他逻辑,比如判断库是主库还是从库。

  • 在异常处理机制上,如果执行FTWRL命令之后由于客户端发生异常断开,那么MySQL会自动释放这个全局锁,整个库回到可以正常更新的状态。而将整个库设置为readonly之后,如果客户端发生异常,则数据库会一直保持该状态,导致整个库长时间处于不可写状态,风险较高。

表级锁

这里介绍两种表级别的锁,一种是表锁,一种是元数据锁。

表锁的语法是lock tables … read/write,可以用unlock tables主动释放锁,也可以在客户端断开时自动释放锁。表锁除了限制其他线程的读写,也限制本线程接下来的操作

在没有出现更细粒度的锁的时候,表锁是最常用的处理并发的方式。对于InnoDB这种支持行锁的引擎,一般不使用lock tables来控制并发。

元数据锁(MDL)不需要显式使用,在访问一个表的时候会被自动加上。其作用是保证读写的正确性。MDL在MySQL 5.5版本引入,当对一个表做增删改查时,会加MDL读锁;当要对表做结构变更操作时,会加MDL写锁。

  • 读锁不互斥,因此可以有多个线程同时对一张表增删改查。

  • 读写锁、写锁之间互斥,用来保证变更表结构操作的正确性。

要注意的是,事务中的MDL锁,在语句执行开始时申请,但语句结束后并不会马上释放,而会等到整个事务提交后释放。考虑下面这样一个例子:

首先事务启动,然后session A会对表t加一个MDL读锁,由于session B需要的也是读锁,第二条查询语句也能正常执行。但之后session C会被阻塞,因为前面的读锁还没释放,而session C需要写锁。当session C阻塞,之后只需要读锁的请求也都会被阻塞,等同于这张表此时完全不可读写。

如果某张表上查询语句频繁,而客户端有重试机制,即超时后再起session请求,那么在上述情况下库的线程很快就会爆满。

基于以上分析,考虑一个场景,假设要对一张小表加字段,这张表数据量不大,但是请求很频繁,该怎么做?

此时因为请求频繁,不能简单kill事务。比较好的方法是,在alter table语句里设置等待时间,如果在等待时间里能拿到MDL写锁就进行修改,拿不到也不阻塞后面的业务语句,先放弃修改,之后开发人员人工介入。

目前已有相应的语句:

ALTER TABLE tbl_name NOWAIT add column ...
ALTER TABLE tbl_name WAIT N add column ...

参考资料:极客时间专栏《MySQL实战45讲》https://time.geekbang.org/column/intro/100020801?tab=catalog

MySQL 06 全局锁和表锁:给表加个字段怎么有这么多阻碍?的更多相关文章

  1. MySQL 笔记整理(6) --全局锁和表锁:给表加个字段怎么有这么多阻碍

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> 6) --全局锁和表锁:给表加个字段怎么有这么多阻碍 数据库锁设计的初衷是处理并发问题.作为多用户共享的资源,当出现并发访问的时候, ...

  2. Mysql实战45讲 06讲全局锁和表锁:给表加个字段怎么有这么多阻碍 极客时间 读书笔记

    Mysql实战45讲 极客时间 读书笔记 Mysql实战45讲 极客时间 读书笔记 笔记体会: 根据加锁范围:MySQL里面的锁可以分为:全局锁.表级锁.行级锁 一.全局锁:对整个数据库实例加锁.My ...

  3. MySQL锁(二)表锁:为什么给小表加字段会导致整个库挂掉?

    概述 表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持.最常使用的MYISAM与INNODB都支持表级锁定.表级锁定分为表共享 ...

  4. 观锁和乐观锁——《POJOs in Action》

    1        事务隔离 事务隔离是数据库提供的功能. SQL Server通过SET TRANSACTION ISOLATION LEVEL语句设置事务隔离级别: SET TRANSACTION ...

  5. EF基础知识小记七(拆分实体到多个表以及拆分表到多个实体)

    一.拆分实体到多个表 1.在日常开发中,会经常碰到一些老系统,当客户提出一些新的需求,这些需求需要在原来的表的基础上加一些字段,大多数人会选择通过给原表添加字段的方式来完成这些需求,方法,虽然可行,但 ...

  6. 【MySQL 读书笔记】全局锁 | 表锁 | 行锁

    全局锁 全局锁是针对数据库实例的直接加锁,MySQL 提供了一个加全局锁的方法, Flush tables with read lock 可以使用锁将整个表的增删改操作都锁上其中包括 ddl 语句,只 ...

  7. MySQL 全局锁、表锁以及行锁

    1. 系统版本 MySQL 5.7.25 ubuntu 16.04 2. 全局锁 全局锁即对整个数据库实例加锁,使得整个库处于只读状态,会阻塞DML和DDL语句.使用如下命令(简称FTWRL)可为数据 ...

  8. MySQL 全局锁和表锁

    根据加锁的范围,MySQL 里面的锁大致可以分成全局锁,表级锁,行锁. 行锁已经在前面几篇文章说过 1. 全局锁 全局锁就是对整个数据库实例加锁.MySQL 提供了一个加全局读锁的方法,命令是Flus ...

  9. MySQL数据库的全局锁和表锁

    1.概念 数据库锁设计的初衷是处理并发问题.作为多用户共享的资源,当出现并发访问的时候,数据库需要合理地控制资源的访问规则.而锁就是用来实现这些访问规则的重要数据结构. 2.锁的分类 根据加锁的范围, ...

  10. MySQL的中的全局锁、表级锁、行锁

    MySQL的中的全局锁.表级锁.行锁 学习极客时间-林晓彬老师-MySQL实战45讲 学习整理 全局锁 对整个数据库实例加锁.通过使用Flush tables with read lock (FTWR ...

随机推荐

  1. 【Linux】远程连接Linux虚拟机(MobaXterm)

    [Linux]远程连接Linux虚拟机(MobaXterm) 零.原因 有时候我们在虚拟机中操作Linux不太方便,比如不能复制粘贴,不能传文件等等,我们在主机上使用远程连接软件远程连接Linux虚拟 ...

  2. restful 服务器一个问题,看ChatGPT的威力 (续)

    资料很多,但是真正能经得住7X24运行的还真不容易.说穿了就是你的程序不够健壮. 玩数据处理的,也就是:数据库连接 → 查询 → 拉数据 → 生成结果 → 释放连接 → 返回数据 .可是看下面: FD ...

  3. ESP32+Arduino入门教程(二):连接OLED屏

    前言 文中视频效果可在此次观看:ESP32+Arduino入门教程(二):连接OLED屏 接线 现在先来看看接线. 我的是0.91寸的4针OLED屏. OLED引脚 ESP32-S3引脚 GND GN ...

  4. 树状数组(Fenwick Tree)原理和优化全面解析

    你正在开发一个交易系统,需要实时完成两种操作: 更新某个时间点的价格(单点修改) 快速计算某段时间段内的交易总量(区间查询) 当数据量较小时,我们可能会这样实现: vector<int> ...

  5. 超实用!用FunctionCall实现快递AI助手

    昨天晚上直播,我们用 RAG(Retrieval-Augmented Generation,检索增强生成)实现了数据库 AI 助手,今天我们准备换一个技术使用 function call 来实现快递 ...

  6. 11.23DP进阶总结

    例.1 Luogu-P1387最大正方形 按如下复杂度来分析 O(\(n^6\)) O(\(n^5\)) O(\(n^3\)) O(\(n^2\log n\)) O(n^2) O(\(n^6\)) 最 ...

  7. Ubuntu修改密码及密码复杂度策略设置方法

    版本查看 cat /etc/issue cat /proc/version 内核查看 uname -a Ubuntu修改密码及密码复杂度策略设置方法 一.修改密码 1.修改普通用户密码 passwd ...

  8. linux期末考试题(1)

    linux期末考试题 一.选择题(共20分,每小题2分) 1.以下哪个环境变量表示shell搜索外部命令或程序路径(C) A.ENV B.PWD C.PATH D.ROOT 解答: ENV用于显示当前 ...

  9. 参考示例之“复制对象|拷贝对象|BeanUtils工具类学习”

    // 设置需要拷贝的字段 Set<String> targetSet = new HashSet<>(); targetSet.addAll(Arrays .asList(&q ...

  10. IDEA问题之“接口路径查询插件【RestfulToolkit】”

    一.场景 只查询Java代码中的路径,这样就可以快速的找到对应的接口 快捷键:Ctrl + \ 二.安装步骤