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

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

yuyutoo 2024-10-12 00:49 11 浏览 0 评论

概述

根据加锁的范围,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方面的内容,感兴趣的朋友可以关注一下~


相关推荐

深度解读Spring框架的核心原理

深度解读Spring框架的核心原理在Java开发的世界里,提到Spring框架,就像提起一位久经沙场的老将,它几乎成了企业级应用开发的代名词。那么,这个被无数开发者膜拜的框架究竟有何独特之处?今天,我...

「Spring认证」Spring 框架概述

Spring是最流行的企业Java应用程序开发框架。全球数以百万计的开发人员使用SpringFramework来创建高性能、易于测试和可重用的代码。Spring框架是一个开源的Java...

学习Spring框架 这一篇就够了

1.spring概述1.1Spring是什么(理解)...

Spring框架双核解析:IOC与AOP的本质与实战

#Spring核心#IOC容器#AOP编程#Java框架设计...

Spring Boot与传统Spring框架的对比:探索Java开发的新境界

SpringBoot与传统Spring框架的对比:探索Java开发的新境界在Java生态系统中,Spring框架无疑是一个里程碑式的存在。从最初的简单依赖注入容器,到如今覆盖企业级开发方方面面的庞大...

Spring MVC框架源码深度剖析:从入门到精通

SpringMVC框架源码深度剖析:从入门到精通SpringMVC框架简介SpringMVC作为Spring框架的一部分,为构建Web应用程序提供了强大且灵活的支持。它遵循MVC(Model-V...

Spring框架入门

一.spring是什么?Spring是分层...

程序员必知必会技能之Spring框架基础——面向切面编程!

面向切面编程AOP(AspectOrientedProgramming)与OOP(ObjectOrientedProgramming,面向对象编程)相辅相成。AOP提供了与OOP不同的抽象软件结...

Spring Security安全框架深度解读:为你的应用穿上“钢铁铠甲”

SpringSecurity安全框架深度解读:为你的应用穿上“钢铁铠甲”在现代网络世界里,保护我们的应用程序免受各种威胁攻击至关重要。而在这个过程中,SpringSecurity框架无疑是我们最可...

Spring框架的设计哲学与实现:打造轻量级的企业级Java应用

Spring框架的设计哲学与实现:打造轻量级的企业级Java应用Spring框架自2003年诞生以来,已成为企业级Java应用开发的代名词。它不仅仅是一个框架,更是一种设计理念和哲学的体现。本文将带你...

Spring框架深度解析:从核心原理到底层实现的全方位避坑指南

一、Spring框架核心概念解析1.控制反转(IoC)与依赖注入(DI)Spring的核心思想是通过IoC容器管理对象的生命周期和依赖关系。传统开发中,对象通过new主动创建依赖对象,导致高耦合;而S...

Java框架 —— Spring简介

简介一般来说,Spring指的是SpringFramework,它提供了很多功能,例如:控制反转(IOC)、依赖注入...

Spring 框架概述,模块划分

Spring框架以控制反转(InversionofControl,IoC)和面向切面编程(Aspect-OrientedProgramming,AOP)为核心,旨在简化企业级应用开发,使开发者...

spring框架怎么实现依赖注入?

依赖注入的作用就是在使用Spring框架创建对象时,动态的将其所依赖的对象注入到Bean组件中,其实现方式通常有两种,一种是属性setter方法注入,另一种是构造方法注入。具体介绍如下:●属性set...

Spring框架详解

  Spring是一种开放源码框架,旨在解决企业应用程序开发的复杂性。一个主要优点就是它的分层体系结构,层次结构让你可以选择要用的组件,同时也为J2EE应用程序开发提供了集成框架。  Spring特征...

取消回复欢迎 发表评论: