mysql 锁详解

目录

前言

一、全局锁

二、表级锁

三、行锁


前言

为什么要设计锁,锁设计初衷是为了解决多线程下并发问题。出现并发的时候用锁进行数据同步,避免因并发造成了数据错误(数据覆盖)。可见锁的重要性,并不是所有的数据库都有锁。比如Redis,单个操作是原子性的,并且是单线程的,并发请求会在队列排列,请求是按顺序执行的,就不需要锁。Mysql 需要锁,mysql 是多线程的,并发操作要保证数据的一致性,需要通过锁进行数据同步。根据锁的范围来讲,mysql 的锁分为全局锁、表级锁和行锁

一、全局锁

全局锁就是对整个数据库实例加锁。Msql 提供的加全局锁的方法,命令是 Flush tables with read lock (FTWRL),以及set global readonly=true那么整库是只读状态,那么对数据库的DDL 以及 DML 将被阻塞,数据库将报下列错误。

全局锁主要是用在全库逻辑备份。这个命令产生以下风险:如果你在主库上备份,那么备份期间不能执行更新,如果在从库上备份,备份期间从库不能执行主库同步过来的binlog,会导致主从延迟。

我们在想想备份为什么要加锁,一定要加锁吗。答案是肯定的,必须的。加锁是为了保证数据的一致性以及业务的完整性。

我们现在有一个订单表,有一个余额表。有用户购买一个产品,业务逻辑是先扣除余额,然后往订单插一条数据。业务期间我们开始备份,在扣除余额前开始备份。恢复数据时候我们发现,用户的余额没有减少,但是用户多了一个订单。是不是不可以呀,所以备份前需要加锁的。加全局锁会影响业务,也是不可取的,有没有其他方法呢。

可以用官方自带的逻辑备份工具mysqldump,当在mysqldump使用参数–single-transaction 的时候,导数据前会启动一个事物,这个事物的隔离级别必须是RR,来确保拿到了一致性视图。由于MVCC 支持,数据库的DML 正常的处理。这种方法需要使用事务引擎的库,MyISAM就不可以。

MyISAM备份还是需要使用FTWRL的。有人说用set global readonly=true也可以让全库只读,可以不,当然也是可以的。他们之间有什么区别呢。一是,修改global变量的方式影响面非常大,readonly会被用来做其他逻辑,比如用来判断一个库是主库还是备库 二是,在异常处理机制的差异。如果客户端异常断开时使用FTWRL会自动释放全局锁,整个库可以正常更新。使用readonly整个库依旧处于只读状态,不能更新。

二、表级锁

在mysql 提供了两种表级别的锁:一种是表锁,二种是元数据锁(meta data lock,MDL)。表锁的语法是 lock tables … read/write,用这种方法的话可以用unlock 去释放锁,也可以客户端断开时自动释放。lock 的影响面很大不仅影响其他线程的write/read,write,本线程接下来的write/也会影响。这种方法毕竟对业务的影响很大,并不常用。

MDL锁,不需要用户显示使用,是mysql 内部的一种机制。当我们对数据表DML时,系统会自动加上MDL读锁,防止用户DDL操作,产生不一致性。当我们对数据表DDL时,系统会自动加上MDL写锁,防止用户DML操作以及其他线程的MDL操作避免数据不一致。

多说一句MDL是一个两阶段锁,在事务开始时加锁,事物结束时释放锁。在这个地方可以给大家解释下,session A , session B , session C, session D 是几个客户端

Session A

此时表加了一个MDL 读锁,事务还没有结束一直保留着MDL 读锁,直到commit 或者 rollback

Session B

此时表加了一个MDL 读锁,读锁之间可以共享

Session C

此时表加了一个MDL 写锁,读锁和写锁之间是互斥的所以阻塞

Session D

此时表加了一个MDL 读锁,由于Session C 被阻塞了所以 Session D也不阻塞了

由此我们可以确定MDL 锁的生命周期是从事务开始到事务提交。上面在解释一下Session D也是MDL读锁为啥也被阻塞了,Session C被阻塞后,后面客户端对表的MDL锁都会放到队列里,当事务提交后,依次从队列取出执行

如何安全的给表修改字段呢?

事务不提交,就会一直占着MDL锁。在 MySQL 的 information_schema 库的 innodb_trx 表中,你可以查到当前执行中的事务。如果你要做 DDL 变更的表刚好有长事务在执行,要考虑先暂停 DDL,或者 kill 掉这个长事务。

下面是如何kil 一个事物

一、在 information_schema 库的 innodb_trx 中找到一个事物id ,然后执行kill 就可以了

如果业务很重要或者表一直有数据更新,那么这种方法不可以了。需要用

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

这种方法,失败了重试,知道成功 。MariaDB 已经合并了 AliSQL 的这个功能,所以这两个开源分支目前都支持 DDL NOWAIT/WAIT n 这个语法。

有人问我mysql 5.6不是支持online ddl了吗?还会有阻塞吗,其实会的。online ddl 执行过程是这样的分为以下几步:

  1. 拿MDL写锁

  2. 降级成MDL读锁

  3. 真正做DDL

  4. 升级成MDL写锁

  5. 释放MDL锁

1、2、4、5如果没有锁冲突,执行时间非常短。第3步占用了DDL绝大部分时间,这期间这个表可以正常读写数据,是因此称为“online ”

我们的例子第一步就锁住了

三、行锁

行锁住要讨论的是innodb引擎下机制,myisam 不支持行锁,也就不支持并发,也就意味着myisam的更新是表级锁。

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

这个机制非常重要,为我们在业务设计中减少锁的冲突提供了理论的支持。那就是说如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。

既然是有锁,对于我们业务开发会不会造成死锁呢,答案是肯定的,什么事死锁呢?

当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁。

当出现死锁后,有两种策略解决死锁:

  1. 一种策略是,直接进入等待,直到超时。这个超时时间可以通过参数 innodb_lock_wait_timeout 来设置。

  2. 另一种策略是,发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑。

在 InnoDB 中,innodb_lock_wait_timeout 的默认值是 50s,意味着如果采用第一个策略,当出现死锁以后,第一个被锁住的线程要过 50s 才会超时退出,然后其他线程才有可能继续执行。对于在线服务来说,这个等待时间往往是无法接受的。如果值设置的太小那么正常的逻辑也有可能受到影响。

innodb_deadlock_detect 这个是有负担的,试想100个线程更新一条记录,那么就有100*100 个量级死锁检测,表的行数越多,会消耗大量的cpu 资源。如果关掉呢,又会一直死锁,直到超时,会影响业务。

那么怎么解决这样的问题呢?

以上两种方案,减少innodb_lock_wait_timeout时间以及 innodb_deadlock_detect=off都是不可取的,那么我们通过减少连接线程去减少并发从而达到减少死锁,后来发现这种方案也是不可靠的,第一、客户端的数量没法控制 第二、减少线程意味着系统的性能得不到完全利用。也只能从业务上去考虑呢,根据不同业务,把更新一行放到多行上,锁的粒度变小了,死锁就减少了。通过这些我们总结一个结论,提高系统性能往往需要确定系统的瓶颈在哪,锁造成的瓶颈,可以考虑减少锁的粒度,比如用分片锁等等

重要:大家有没有想过行锁是加在哪呢,是在索引上,意味着我们在update 时候,wehere 没有设置索引,那么只要扫描的记录都会加上索引,事务提交的时候统一释放。所以update 更新语句一定要记住加上索引,由于update 是当前读的,没有加上索引一定是灾难性的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/694229.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是CODESYS开发系统

CODESYS是一种用于工业自动化领域的开发系统软件,提供了一个完整集成的开发环境。该软件由德国CODESYS GmbH(原 3S-Smart Software Solutions GmbH)公司开发,其最新版本为CODESYS V3。 CODESYS开发系统具有多种特性和优点。首先&a…

⭐北邮复试刷题105. 从前序与中序遍历序列构造二叉树__递归分治 (力扣每日一题)

105. 从前序与中序遍历序列构造二叉树 给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。 示例 1: 输入: preorder [3,9,20,15,7], inorder [9,3,15,…

Rocky 8.9 Kubespray v2.24.0 在线部署 kubernetes v1.28.6 集群

文章目录 1. 简介2. 预备条件3. 基础配置3.1 配置hostname3.2 配置互信 4. 配置部署环境4.1 在线安装docker4.2 启动容器 kubespray4.3 编写 inventory.ini4.4 关闭防火墙、swap、selinux4.5 配置内核模块 5. 部署6. 集群检查 1. 简介 kubespray​ 是一个用于部署和管理 Kuber…

抽象方法与设计模式

抽象方法与设计模式 设计模式的六大原则工厂模式单例模式建造者模式过滤器模式装饰器模式享元模式责任链模式模板模式 真正的屎山不是初级程序员写的巨量胶水代码,而是没学明白抽象的程序员写的大量设计模式耦合形成的。你甚至不理解为什么当初的创作者需要使用到这…

基于postMessage和BroadcastChannel实现浏览器跨Tab窗口通信的方法介绍

文章目录 一、Broadcast Channel1、创建实例2、监听消息3、发送消息4、关闭5、示例演示5.1、主控页面5.2、受控页面 二、postMessage1、语法1.1、targetWindow1.2、message1.3、targetOrigin1.4、transfer(可选的) 2、示例演示2.1、parent页面2.2、child…

Elsevier投稿录用后的一些疑问

在elsevier投稿被录用之后,会收到好几个邮件: 第一封邮件是给你一个在线修改稿子的网站,让你核实作者,文献等等的信息,以及编辑做的修改,要注意的是有几个query问题是必须回答的。然后你在线修改完提交就可…

CF1468J Road Reform 题解

CF1468J Road Reform 题解 link CF1468J Road Reform 题面翻译 给定一个有 n n n 个节点, m m m 条无向带权边的图,和一个参数 k k k,第 i i i 条边权值为 s i s_i si​。 现在你要保留这个图中的 n − 1 n-1 n−1 条边使得这个图变…

java导出动态下拉框excel模板

1.原始模板 2.导出模板,下拉框为数据库中得到动态数据 public void downloadTemplate(HttpServletResponse response) throws IOException {// 所有部门List<String, String> departments expertManageMapper.selectAllDepartment();//所有职位List<String, String&g…

前端关于Vue跳转外部链接(百度为例)

一定要加这句 window.location.href http://www.baidu.com/s?wd this.wd;关于Vue跳转外部链接&#xff08;百度为例&#xff09;_vue3.2 点击按钮 router.resolve 跳转 百度-CSDN博客 <img src"./hd1.jpg" width"200px" height"100px" c…

模块 time:时间和日期处理

MicroPython内置模块 time&#xff1a;时间和日期处理 MicroPython的内置模块time是一个用于处理时间相关功能的模块&#xff0c;它实现了CPython模块的一个子集&#xff0c;但也有一些特殊的特点和限制。本文将从以下几个方面介绍time模块的主要特点、应用场景&#xff0c;以…

基于Java (spring-boot)的社区物业管理系统

一、项目介绍 本系统共分为两个角色&#xff1a;管理员和业主。 主要功能有&#xff0c;核心业务处理&#xff0c;基础信息管理&#xff0c;数据统计分析 核心业务处理&#xff1a;车位收费管理&#xff0c;物业收费管理&#xff0c;投诉信息管理&#xff0c;保修信息管理。 …

Top-N 泛型工具类

一、代码实现 public class TopNUtil<E extends Comparable<E>> {private final PriorityQueue<E> priorityQueue;private final int n;/*** 构造 Top-N*/public TopNUtil(int size) {if (size < 0) {throw new IllegalArgumentException("Top-N si…

嵌入式学习day22 Linux

文件IO: 1. lseek off_t lseek(int fd, off_t offset, int whence); 功能: 重新设定文件描述符的偏移量 参数: fd:文件描述符 offset:偏移量 whence: SEEK_SET 文件开头 …

代码随想录三刷day04

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、力扣209. 长度最小的子数组二、力扣904. 水果成篮三、力扣76. 最小覆盖子串 前言 接下来就开始介绍数组操作中另一个重要的方法&#xff1a;滑动窗口。 所谓…

C++从入门到精通 第十四章(STL容器)【下】

七、list容器 1、list的基本概念 &#xff08;1&#xff09;list的功能是将数据进行链式存储&#xff0c;对应数据结构中的链表&#xff0c;链表是一种物理存储单元上非连续的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接实现的。 &#xff08;2&#xff…

《VitePress 简易速速上手小册》第2章:Markdown 与页面创建(2024 最新版)

文章目录 2.1 Markdown 基础及扩展2.1.1 基础知识点解析2.1.2 重点案例&#xff1a;技术博客2.1.3 拓展案例 1&#xff1a;食谱分享2.1.4 拓展案例 2&#xff1a;个人旅行日记 2.2 页面结构与布局设计2.2.1 基础知识点解析2.2.2 重点案例&#xff1a;公司官网2.2.3 拓展案例 1&…

Linux系统运维:性能监视和分析工具sar命令详解

目 录 一、sar工具介绍 二、sar工作原理 &#xff08;一&#xff09;原理概述 &#xff08;二&#xff09;sar数据收集器 三、sar命令语法 四、sar主要功能介绍 &#xff08;一&#xff09;功能概述 &#xff08;二&#xff09;CPU统计数据 &#xff08;三&a…

jwt+redis实现登录认证

项目环境&#xff1a;spring boot项目 pom.xml引入jwt和redis <!-- jwt --><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.3.0</version></dependency><!-- redis坐标-->…

数据结构与算法:队列

在上篇文章讲解了栈之后&#xff0c;本篇也对这一章进行收尾&#xff0c;来到队列&#xff01; 队列 队列的介绍队列的存储结构队列顺序存储的不足之处 循环队列的定义队列的链式存储结构链队列的构建链队列的初始化队尾入队队头出队获取队头队尾元素判断队列是否为空获取队列元…

Spark解决代码变量bug:error: reassingnment to val

在Scala中&#xff0c;val关键字用于声明一个不可变的变量&#xff0c;一旦赋值后就不能再更改。这就是为什么我尝试重新赋值给modelFilePath时会收到“reassignment to val”的错误。 modelFilePath的声明从val更改为var&#xff0c;因为var允许我们重新赋值 样例代码 val …