百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 博客教程 > 正文

面试官:说说你对mysql数据库全局锁,表级锁,行锁的理解?

connygpt 2024-09-09 03:11 16 浏览

概述

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


1、全局锁

全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法,命令是Flush tables with read lock (FTWRL)。

当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。

1.1 全局锁使用场景

全局锁的典型使用场景是,做全库逻辑备份(mysqldump)。重新做主从时候

也就是把整库每个表都 select 出来存成文本。

以前有一种做法,是通过 FTWRL 确保不会有其他线程对数据库做更新,然后对整个库做备份。注意,在备份过程中整个库完全处于只读状态。

数据库只读状态的危险性:

如果你在主库上备份,那么在备份期间都不能执行更新,业务基本上就能停止。如果你在从库上备份,那么备份期间从库不能执行主库同步过来的binlog,会导致主从延迟。

注:上面逻辑备份,是不加--single-transaction参数

看来加全局锁不太好。但是细想一下,备份为什么要加锁呢?来看一下不加锁会有什么问题?

1.2 不加锁产生的问题

比如手机卡,购买套餐信息

这里分为两张表 u_acount (用于余额表),u_pricing (资费套餐表)

步骤:

1 . u_account 表中数据 用户A 余额:300

u_pricing 表中数据 用户A 套餐:空

2. 发起备份,备份过程中先备份u_account表,备份完了这个表,这个时候u_account 用户余额是300

3. 这个时候套用户购买了一个资费套餐100,餐购买完成,写入到u_print套餐表购买成功,备份期间的数据。

4. 备份完成

可以看到备份的结果是,u_account 表中的数据没有变, u_pricing 表中的数据已经购买了资费套餐100。也就是说,不加锁的话,备份系统备份的得到的库不是一个逻辑时间点,这个数据是逻辑不一致的。

1.3 为什么需要全局读锁(FTWRL)

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

为什么还需要 FTWRL 呢?

一致性读是好,但前提是引擎要支持这个隔离级别。比如,对于 MyISAM 这种不支持事务的引擎,如果备份过程中有更新,总是只能取到最新的数据,那么就破坏了备份的一致性。这时,我们就需要使用FTWRL 命令了。

所以,single-transaction 方法只适用于所有的表使用事务引擎的库。如果有的表使用了不支持事务的引擎,那么备份就只能通过 FTWRL 方法。这往往是 DBA 要求业务开发人员使用 InnoDB 替代 MyISAM 的原因之一。

1.4 全局锁两种方法

一.FLUSH TABLES WRITE READ LOCK

二.set global readonly=true

既然要全库只读,为什么不使用 set global readonly=true 的方式呢?确实 readonly 方式也可以让全库进入只读状态,但我还是会建议你用 FTWRL 方式,主要有几个原因:

一是,在有些系统中,readonly 的值会被用来做其他逻辑,比如用来判断一个库是主库还是备库。因此,修改 global 变量的方式影响面更大,我不建议你使用。

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

三是,readonly 对super用户权限无效

注 :业务的更新不只是增删改数据(DML),还有可能是加字段等修改表结构的操作(DDL)。不论是哪种方法,一个库被全局锁上以后,你要对里面任何一个表做加字段操作,都是会被锁住的。

即使没有被全局锁住,加字段也不是就能一帆风顺的,还有表级锁了


2、表级锁

MySQL 中表级别锁有两种:一种是普通表锁,一种是元数据锁(metadata lock. MDL)

表锁的语法是 lock tables xxx read/write 同样使用 unlock tables 来释放锁。通过加读锁我们可以限制其他语句进行写入,但是重复加读锁不受影响。但是当我们加写锁的时候,既不可以读也不可以写。同样在使用 unlock tables 之后可以解除锁定。

另外一种表级锁是 MDL 锁(metadata lock) MDL 锁不需要显示的使用,在访问一个表的时候自动就被加上了。 MDL 锁是用来保证读写正确性的,当我们对一个表在做 增删改查操作的时候都会被加上 MDL 读锁。当要进行 ddl 的时候需要加 MDL 写锁。

MDL 读锁与读锁之间不互斥,因此我们可以多个线程进程对一个表进行增删改查。

MDL 读写锁之间互斥,用来保证表结构变更的安全性。因此如果有两个线程同时要给同一个表加字段,其中一个要等另外一个执行完成之后再开始执行。

下面我们来看一个比较有代表性的场景 MDL 读锁写锁互斥导致表无法读写被死锁。

  • session A: 开始一个事务,然后查询 t 表,这会给 t 表加上 MDL 读锁。(注意该事务被打开后就一直没有结束)
  • session B: 查询一个 t 表。这里应该是 autoocommit 会自动成功。
  • session C: 修改表 ddl 会加 MDL 写锁,和 session A 的读锁互斥。这个时候就锁住了表。
  • session D: 由于 session C 造成了写锁阻塞,所以后面所有的请求都会被锁住。

如果该表查询频繁,而且客户端有重试的机制,那么这个数据库的查询线程会很快被打满。

可能在进行 web 开发的同学会经常遇到类似的情况。比如我在 ipython 里面打开了一个数据库某个表的连接,然后我一直没有 commit 。就可能造成该表在加写锁的时候阻塞后面所有的操作。

这种事情非常常见。

那么我们如何安全的给小表加字段,首先我们应该解决长事务或者脚本事务的问题,因为他们会一直挂读锁不结束。在 MySQL 的 information_schema 中的 innodb_trx 中可以查询到执行中的长事务,但是比较麻烦的是这个看不到很短的事务。但是往往进行 sleep 的短事务也可能因为一直没有 commit 而导致上面的情况出现。

这个时候就需要把对应表的 sleep 进程 kill 掉使其恢复正常。


3、行级锁

先来看个描述两阶段锁的例子:

事务 A 会持有两条记录的行锁,并且只会在 commit 之后才会释放。

在 InnoDB 事务中,行锁是在需要的时候加上,但是并不是不需要就立刻释放,而是等事务结束之后才会释放。这个就是两阶段锁协议。

知道了这个设定我们应该在长事务中把影响并发度的锁尽量往后放。下面的这一段的介绍比较复杂,我觉得丁奇讲得还是比较清楚的所以直接引用原文了。

假设你负责实现一个电影票在线交易业务,顾客 A 要在影院 B 购买电影票。我们简化一点,这个业务需要涉及到以下操作:

1. 从顾客 A 账户余额中扣除电影票价;

2. 给影院 B 的账户余额增加这张电影票价;

3. 记录一条交易日志。

也就是说,要完成这个交易,我们需要 update 两条记录,并 insert 一条记录。当然,为了保证交易的原子性,我们要把这三个操作放在一个事务中。那么,你会怎样安排这三个语句在事务中的顺序呢?

试想如果同时有另外一个顾客 C 要在影院 B 买票,那么这两个事务冲突的部分就是语句 2 了。因为它们要更新同一个影院账户的余额,需要修改同一行数据。

根据两阶段锁协议,不论你怎样安排语句顺序,所有的操作需要的行锁都是在事务提交的时候才释放的。所以,如果你把语句 2 安排在最后,比如按照 3、1、2 这样的顺序,那么影院账户余额这一行的锁时间就最少。这就最大程度地减少了事务之间的锁等待,提升了并发度。


后面会分享更多devops和DBA方面的内容,感兴趣的朋友可以关注一下~


相关推荐

3分钟让你的项目支持AI问答模块,完全开源!

hello,大家好,我是徐小夕。之前和大家分享了很多可视化,零代码和前端工程化的最佳实践,今天继续分享一下最近开源的Next-Admin的最新更新。最近对这个项目做了一些优化,并集成了大家比较关注...

干货|程序员的副业挂,12个平台分享

1、D2adminD2Admin是一个完全开源免费的企业中后台产品前端集成方案,使用最新的前端技术栈,小于60kb的本地首屏js加载,已经做好大部分项目前期准备工作,并且带有大量示例代码,助...

Github标星超200K,这10个可视化面板你知道几个

在Github上有很多开源免费的后台控制面板可以选择,但是哪些才是最好、最受欢迎的可视化控制面板呢?今天就和大家推荐Github上10个好看又流行的可视化面板:1.AdminLTEAdminLTE是...

开箱即用的炫酷中后台前端开源框架第二篇

#头条创作挑战赛#1、SoybeanAdmin(1)介绍:SoybeanAdmin是一个基于Vue3、Vite3、TypeScript、NaiveUI、Pinia和UnoCSS的清新优...

搭建React+AntDeign的开发环境和框架

搭建React+AntDeign的开发环境和框架随着前端技术的不断发展,React和AntDesign已经成为越来越多Web应用程序的首选开发框架。React是一个用于构建用户界面的JavaScrip...

基于.NET 5实现的开源通用权限管理平台

??大家好,我是为广大程序员兄弟操碎了心的小编,每天推荐一个小工具/源码,装满你的收藏夹,每天分享一个小技巧,让你轻松节省开发效率,实现不加班不熬夜不掉头发,是我的目标!??今天小编推荐一款基于.NE...

StreamPark - 大数据流计算引擎

使用Docker完成StreamPark的部署??1.基于h2和docker-compose进行StreamPark部署wgethttps://raw.githubusercontent.com/a...

教你使用UmiJS框架开发React

1、什么是Umi.js?umi,中文可发音为乌米,是一个可插拔的企业级react应用框架。你可以将它简单地理解为一个专注性能的类next.js前端框架,并通过约定、自动生成和解析代码等方式来辅助...

简单在线流程图工具在用例设计中的运用

敏捷模式下,测试团队的用例逐渐简化以适应快速的发版节奏,大家很早就开始运用思维导图工具比如xmind来编写测试方法、测试点。如今不少已经不少利用开源的思维导图组件(如百度脑图...)来构建测试测试...

【开源分享】神奇的大数据实时平台框架,让Flink&Spark开发更简单

这是一个神奇的框架,让Flink|Spark开发更简单,一站式大数据实时平台!他就是StreamX!什么是StreamX大数据技术如今发展的如火如荼,已经呈现百花齐放欣欣向荣的景象,实时处理流域...

聊聊规则引擎的调研及实现全过程

摘要本期主要以规则引擎业务实现为例,陈述在陌生业务前如何进行业务深入、调研、技术选型、设计及实现全过程分析,如果你对规则引擎不感冒、也可以从中了解一些抽象实现过程。诉求从硬件采集到的数据提供的形式多种...

【开源推荐】Diboot 2.0.5 发布,自动化开发助理

一、前言Diboot2.0.5版本已于近日发布,在此次发布中,我们新增了file-starter组件,完善了iam-starter组件,对core核心进行了相关优化,让devtools也支持对IAM...

微软推出Copilot Actions,使用人工智能自动执行重复性任务

IT之家11月19日消息,微软在今天举办的Ignite大会上宣布了一系列新功能,旨在进一步提升Microsoft365Copilot的智能化水平。其中最引人注目的是Copilot...

Electron 使用Selenium和WebDriver

本节我们来学习如何在Electron下使用Selenium和WebDriver。SeleniumSelenium是ThoughtWorks提供的一个强大的基于浏览器的开源自动化测试工具...

Quick 'n Easy Web Builder 11.1.0设计和构建功能齐全的网页的工具

一个实用而有效的应用程序,能够让您轻松构建、创建和设计个人的HTML网站。Quick'nEasyWebBuilder是一款全面且轻巧的软件,为用户提供了一种简单的方式来创建、编辑...