性能调优专题(5)之深入理解Mysql事务隔离级别与锁机制

news2024/11/7 22:16:42

一、概述

        我们的数据库一般都会并发执行多个事务,多个事务可能会并发的对相同的一批数据进行增删改查操作,可能就会导致我们说的脏写、脏读、不可重复读、幻读这些问题。

        这些问题的本质都是数据库的多并发事务问题,为了解决多事务并发问题,数据库设计了事务的隔离级别、锁机制、MVCC多版本并发控制隔离机制,用一整套机制来解决多事务并发问题。接下来我们会深入讲解这些机制,让大家彻底理解数据库内部的执行原理。

二、事务及其ACID属性

        事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的ACID属性。

  • 原子性(Atomicity):事务是一个原子操作单位,对其数据的修改,要么全部执行,要么全都不执行。
  • 一致性(Consistent):在事务开始和完成时,数据都必须保持一致性。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性。
  • 隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的独立环境执行,这意味着事务处理过程中的中间状态对外部是不可见的。
  • 持久性(Durable):是我完成后,他对于数据的修改是永久性的,及时出现了系统故障也能保持。

2.1 并发事务带来的问题

        更新丢失(Lost Update)或脏写:当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其他事务所做的更新。

        脏读(Dirty Reads):一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致的状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此作进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象的叫做“脏读”。

      不可重读(Non-Repeatable Reads):  一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做“不可重复读”。一句话:事务A内部的相同查询语句在不同时刻读出的结果不一致,不符合隔离性。

        幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。一句话:事务A读取到了事务B提交的新增数据,不符合隔离性

2.2 事务隔离级别

        “脏读”、“不可重复读”和“幻读”,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。

隔离级别

脏读(Dirty Read)

不可重复读(NonRepeatable Read)

幻读(Phantom Read)

读未提交(Read uncommitted)

可能

可能

可能

读已提交(Read committed)

不可能

可能

可能

可重复读(Repeatableread)

不可能

不可能

可能

可串行化

(Serializable)

不可能

不可能

不可能

         数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的。

        同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,比如许多应用对“不可重复读"和“幻读”并不敏感,可能更关心数据并发访问的能力。

三、锁机制

        锁是计算机协调多个进程或线程并发访问某一资源的机制。

        在数据库中,除了传统的计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供需要用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。

3.1 锁分类                

  • 从性能上分为乐观锁和悲观锁
  • 从数据操作的粒度分为表锁和行锁
  • 从对数据库操作的类型分为读锁和写锁(都属于是悲观锁),还有意向锁;

        读锁(共享锁,S锁(Shared)):针对同一份数据,多个读操作可以同时进行而不会相互影响,比如:select * from T where id = 1 lock in share mode;

         写锁(排它锁,X锁(eXclusive)):当前写操作没有完成之前,它会阻断其他写锁和读锁,数据修改操作都会加写锁,查询也可以通过for update加写锁,比如:select * from T where id=1 for update;

        意向锁(Intention Lock):意向锁,又称为I锁,针对表锁,主要是为了提高加表锁的效率,是mysql数据库自己加的。当有事务给表的数据行加了共享锁或者是排它锁,同时会给表设置一个标记,代表已经有了行锁了,其他事务想要对表加表锁时,就不必逐行的去判断有没有行锁了,直接读这个标记就可以确定自己该不该加表锁。。特别是表中的记录很多时,逐行判断加表锁的方式效率非常低,而这个标记就是意向锁。

        意向锁主要分为:

        意向共享锁,IS锁,对整个表加共享锁之前,需要获取得到意思共享锁。

        意向排它锁,IX锁,对整个表加排它锁之前,需要先获取意思排它锁。

3.2 表锁

        每次操作锁住整张表。开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;一般用在整表数据迁移的场景。

--建表SQL
CREATE TABLE `mylock` (
	`id` INT (11) NOT NULL AUTO_INCREMENT,
	`NAME` VARCHAR (20) DEFAULT NULL,
	PRIMARY KEY (`id`)
) ENGINE = MyISAM DEFAULT CHARSET = utf8;

--插入数据
INSERT INTO`test`.`mylock` (`id`, `NAME`) VALUES ('1', 'a');
INSERT INTO`test`.`mylock` (`id`, `NAME`) VALUES ('2', 'b');
INSERT INTO`test`.`mylock` (`id`, `NAME`) VALUES ('3', 'c');
INSERT INTO`test`.`mylock` (`id`, `NAME`) VALUES ('4', 'd');

        手动增加表锁: lock table 表名称 read(write),表名称2 read(write);

3.3 行锁

         每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最高。

        InnoDB与MYISAM的最大不同有两点:

  • InnoDB支持事务(TRANSACTION)
  • InnoDB支持行锁

四、行锁与事务隔离级别案例分析

        1、读未提交:

        (1)打开一个客户端A,并设置当前事务模式为read uncommitted(未提交读),查询表account的初始值:

set tx_isolation='read-uncommitted';

        (2)在客户端A的事务提交之前,打开另一个客户端B,更新表account: 

         (3)这时,虽然客户端B的事务还没提交,但是客户端A就可以查询到B已经更新的数据: 

        (4)一旦客户端B的事务因为某种原因回滚,所有的操作都将会被撤销,那客户端A查询到的数据其实就是脏数据: 

        (5)在客户端A执行更新语句update account set balance = balance - 50 where id =1,lilei的balance没有变成350,居然是400,是不是很奇怪,数据不一致啊,如果你这么想就太天真 了,在应用程序中,我们会用400-50=350,并不知道其他会话回滚了,要想解决这个问题可以采用读已提交的隔离级别。【update使用的是当前读】

2、读已提交

        (1)打开一个客户端A,并设置当前事务模式为read committed(未提交读),查询表account的所有记录:

         (2)在客户端A的事务提交之前,打开另一个客户端B,更新表account: 

         (3)这时,客户端B的事务还没提交,客户端A不能查询到B已经更新的数据,解决了脏读问题: 

        (4)客户端B的事务提交 

         (5)客户端A执行与上一步相同的查询,结果 与上一步不一致,即产生了不可重复读的问题。

 3、可重复读

        (1)打开一个客户端A,并设置当前事务模式为repeatable read,查询表account的所有记录。

        (2)在客户端A的事务提交之前,打开另一个客户端B,更新表account并提交。

         (3)在客户端A查询表account的所有记录,与步骤(1)查询结果一致,没有出现不可重复读的问题。

        (4)在客户端A,接着执行update account set balance = balance - 50 where id = 1,balance没有变成400-50=350,lilei的balance值用的是步骤2中的350来算的,所以是300,数据的一致性倒是没有被破坏。可重复读的隔离级别下使用了MVCC(multi-version concurrency control)机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。

 

        (5)重新打开客户端B,插入一条新数据后提交 。

         (6)在客户端A查询表account的所有记录,没有查出新增数据,所以没有出现幻读。

        (7)验证幻读

        在客户端A执行update account set balance=888 where id = 4;能更新成功,再次查询能查到客户端B新增的数据

        4、串行化

        (1)打开一个客户端A,并设置当前事务模式为serializable,查询表account的初始值。

         (2)打开一个客户端B,并设置当前事务模式为serializable,更新相同的id为1的记录会被阻塞等待,更新id为2的记录可以成功,说明在串行模式下innodb的查询也会被加上行锁。

        如果客户端A执行的是一个范围查询,那么该范围内的所有行包括每行记录所在的间隙区间范围(就算该行数据还未被插入也会加锁,这种是间隙锁)都会被加锁。此时如果客户端B在该范围内插入数据都会被阻塞,所以就避免了幻读。

4.1 间隙锁

        间隙锁,锁的就是两个值之间的空隙。Mysql默认级别是repeatable-read,有办法解决幻读问题吗?间隙锁在某些情况下可以解决幻读问题。

        假设account表里数据如下:

         那么间隙就有 id 为 (3,10),(10,20),(20,正无穷) 这三个区间,在Session_1下面执行 update account set name = 'zhuge' where id > 8 and id 范围所包含的所有行记录(包括间隙行记录)以及行记录所在的间隙里插入或修改任何数据,即id在(3,20]区间都无法修改数据,注意最后那个20也是包含在内的。

        注意:间隙锁是在可重复读隔离级别下才会生效。

4.2 临键锁

      Next-Key Locks是行锁与间隙锁的组合。像上面那个例子里的这个(3,20]的整个区间可以叫做临键锁。  

        无索引行锁会升级为表锁(RR级别会升级为表锁,RC级别不会升级为表锁)。

        锁主要是加在索引上,如果对非索引字段更新,行锁可能会变表锁。

        session1 执行:update account set balance = 800 where name = 'lilei';

        session2 对该表任一行操作都会阻塞住。

        InnoDB的行锁是针对索引加的锁,不是针对记录加的锁。并且该索引不能失效,否则都会从行锁升级为表锁。

        锁定某一行还可以用lock in share mode(共享锁) 和for update(排它锁),例如:select * from test_innodb_lock where a = 2 for update; 这样其他session只能读这行数据,修改则会被阻塞,直到锁定行的session提交。

        结论:Innodb存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更高一下,但是在整体并发处理能力方面要远远优于MYISAM的表级锁定的。当系统并发量高的时候,Innodb的整体性能和MYISAM相比就会有比较明显的优势了。

        但是,Innodb的行级锁定同样也有其脆弱的一面,当我们使用不当的时候,可能会让Innodb的整体性能表现不仅不能比MYISAM高,甚至可能会更差。

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

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

相关文章

CentOS 7 软件/程序安装示例

安装软件/程序 wget,前提需要用 root 用户 1、搜索软件/程序 yum search wget 搜索到软件/程序。 2、安装软件/程序 yum -y install wget 安装完成。 ---------------------------------------------------------------------------------------------------…

MySQL详细安装教程

一、从MySQL官网安装 可以翻译成中文看起来就舒服多了 下载并打开安装包,能看到版本是8.0.36,双击运行或者右键选择打开,打开后是一个安装向导,这个安装向导会先帮我们安装一个 mysql-installer 的程序,再通过该程序安…

Dubbo使用Nacos作为注册中心

使用 Nacos 作为注册中心实现自动服务发现 本示例演示 Nacos 作为注册中心实现自动服务发现&#xff0c;示例基于 Spring Boot 应用展开&#xff0c;可在此查看 完整示例代码 1 基本配置 1.1 增加依赖 增加 dubbo、nacos-client 依赖&#xff1a; <dependencies><…

洗衣小程序/洗鞋小程序 洗衣店系统,洗衣系统源码

多城市洗衣店小程序&#xff0c;对接京东物流&#xff0c;支持城市合伙人&#xff0c;支持在线商城&#xff0c;在线预约下单 支持抖音验券支持 支持电子券 支持水洗码

数据结构 —— 红黑树

目录 1. 初识红黑树 1.1 红黑树的概念 1.2 红⿊树的规则 1.3 红黑树如何确保最长路径不超过最短路径的2倍 1.4 红黑树的效率:O(logN) 2. 红黑树的实现 2.1 红黑树的基础结构框架 2.2 红黑树的插⼊ 2.2.1 情况1&#xff1a;变色 2.2.2 情况2&#xff1a;单旋变色 2.2…

吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)4.11

目录 第四门课 卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;第四周 特殊应用&#xff1a;人脸识别和神经风格转换&#xff08;Special applications: Face recognition &Neural style transfer&#xff09;4.11 一维到三维推广&#xff08;1D and 3…

unity3d————四元数概念

一、定义与表示 四元数是由一个实数部分和三个虚数部分组成&#xff0c;通常表示为q w xi yj zk&#xff0c;其中w是实数&#xff0c;x、y、z是实数系数&#xff0c;i、j、k是虚数单位&#xff0c;满足以下关系&#xff1a; i j k -1ij k&#xff0c;ji -kjk i&…

大数据分库分表方案

分库分表介绍 分库分表应用场景 分库分表介绍 大数据分库分表是一种数据库架构技术&#xff0c;旨在应对大数据量场景下的数据库性能瓶颈。以下是对大数据分库分表的详细解释&#xff1a; 一、定义与背景 定义&#xff1a; 分库&#xff1a;将一个大型数据库按照一定的规则…

可重入函数 volatile SIGCHLD

目录 1. 可重入函数2. volatile3. SIGCHLD 信号 1. 可重入函数 场景&#xff1a;当我们在全局区定义一个链表&#xff08;不带头结点&#xff09;&#xff0c;然后对链表做头插结点的操作&#xff0c;即插入 node1 结点&#xff08;如上图所示&#xff09;。在插入 node1 时需要…

『VUE』20. 组件嵌套关系page(详细图文注释)

目录 VUE的自带组件结构新建文件搭建结构app与Main Header Aside结构App.vueHeader.vueMain.vueAside.vue Main 与Article.Aside与Item结构Article.vueItem.vue 总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 因为前面已经有…

【Hive sql面试题】找出连续活跃3天及以上的用户

表数据如下&#xff1a; 要求&#xff1a;求出连续活跃三天及以上的用户 建表语句和插入数据如下&#xff1a; create table t_useractive(uid string,dt string );insert into t_useractive values(A,2023-10-01 10:10:20),(A,2023-10-02 10:10:20),(A,2023-10-03 10:16…

【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-16

文件下载与邀请翻译者 学习英特尔开发手册&#xff0c;最好手里这个手册文件。原版是PDF文件。点击下方链接了解下载方法。 讲解下载英特尔开发手册的文章 翻译英特尔开发手册&#xff0c;会是一件耗时费力的工作。如果有愿意和我一起来做这件事的&#xff0c;那么&#xff…

Vulnhub靶机——DC-3

#环境准备 dc-3 虚拟机&#xff1a;网卡NAT模式 kali攻击机&#xff1a;网卡NAT模式 #信息收集 nmap轻车熟路扫一下dc3的地址&#xff0c;识别出joomla系统 面向百度渗透&#xff0c;得知有一个joomla的扫描器&#xff0c;直接安排上&#xff0c;这下有版本号和后台登录地址…

数据结构:七种排序及总结

文章目录 排序一插入排序1直接插入排序2希尔排序二选择排序3直接选择排序4堆排序三 交换排序5冒泡排序6快速排序四 归并排序7归并排序源码 排序 我们数据结构常见的排序有四大种&#xff0c;四大种又分为七小种&#xff0c;如图所示 排序&#xff1a;所谓排序&#xff0c;就是…

基于STM32H7XX的Bootloader启动与FOTA

1. Bootloader是如何工作的: 2.正常情况下,程序从flash启动时的启动流程,如下图所示: 首先程序从flash启动,根据中断向量表找到复位中断处理函数的地址(0x0800 0004处是中断向量表的起始地址,记录了复位中断处理函数的地址)。执行复位中断处理函数,初始化系统环境之后…

语音 AI 迎来爆发期,也仍然隐藏着被低估的机会丨RTE2024 音频技术和 Voice AI 专场

在人工智能快速发展的今天&#xff0c;语音交互技术正经历一场革命性的变革。从语音识别到语音合成&#xff0c;再到端到端的语音对话系统&#xff0c;这一领域的创新正以前所未有的速度推进。这些进步不仅提升了技术指标&#xff0c;更为实时翻译、虚拟数字人、智能客服等实时…

【自学笔记】神经网络(1)

文章目录 介绍模型结构层&#xff08;Layer&#xff09;神经元 前向传播反向传播Q1: 为什么要用向量Q2: 不用激活函数会发生什么 介绍 我们已经学习了简单的分类任务和回归任务&#xff0c;也认识了逻辑回归和正则化等技巧&#xff0c;已经可以搭建一个简单的神经网络模型了。 …

在内蒙考驾照需要注意什么呢?

一、报名条件 年满18周岁&#xff0c;具有完全民事行为能力的中国公民。持有有效的身份证明文件。身体健康&#xff0c;无妨碍驾驶机动车的疾病&#xff0c;并需要通过体检。 二、选择驾校 可以先向身边已经拿到驾照的朋友咨询&#xff0c;了解驾校的距离、位置、口碑等信息。…

C++builder中的人工智能(8)什么是神经网络中的恒等激活函数?

在这篇文章中&#xff0c;我们将回答以下问题&#xff1a; 你想了解神经网络中最简单的激活函数是什么吗&#xff1f;什么是恒等函数&#xff1f;作为AI术语&#xff0c;我们需要了解激活函数和转移函数的哪些知识&#xff1f;激活函数与净输入函数是一回事吗&#xff1f;是否…

django图书管理系统-计算机毕业设计源码00648

摘要 图书管理系统在数字化阅读趋势、图书馆自动化管理、用户体验需求和信息技术应用等方面具有重要的研究意义。图书馆自动化管理系统的引入和应用提高了图书借阅过程的效率和准确性&#xff0c;减少了对手工操作和纸质记录的需求。用户对系统的易用性、查询速度、借还流程有更…