数据库原理及MySQL应用 | 并发控制

news2024/10/1 7:29:29

 无论何时,只要有多个查询需要在同一时刻修改数据,都会产生并发控制问题,MySQL通过多版本并发控制和加锁实现并发控制。

多用户并发执行事务访问同一个数据库时,可能引发脏写、脏读、不可重复读、幻读等一致性问题。并发事务访问相同记录的情况,可分为以下三种。

1. 读-读

即多个并发事务相继读取相同的记录。这种情况是允许的,因为读取操作不会修改记录的内容。

2. 写-写

即多个并发事务相继对相同的记录进行修改。这种情况下会发生“脏写”现象,任何一种隔离级别都不允许这种现象发生。此时,需要通过锁机制,使这些未提交的并发事务排队依次执行。

当一个事务想对这条记录进行改动时,需要先加锁,加锁成功事务才能继续操作;若加锁失败事务需要等待。

3. 读-写或写-读

即一个事务在进行读操作,另一个事务在进行写操作。这种情况下可能会出现脏读、不可重复读、幻读的现象。MySQL采用了以下两种解决方案。

(1) 读操作使用多版本并发控制(MVCC),写操作进行加锁。

(2) 读操作和写操作都采用加锁的方式。

采用MVCC方式,读操作和写操作彼此并不冲突,性能更高。而采用加锁方式,读操作和写操作需要排队执行,从而影响性能。

一般情况下,可以采用MVCC来解决读操作和写操作并发执行的问题,但一些业务场景要求每次都必须读取记录的最新版,不允许读取记录的旧版本,这种情况下就只能采用加锁的方式了。

01、MVCC

MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种用来解决读-写冲突的无锁并发控制机制,在数据库中用来控制并发执行的事务,使事务隔离进行。其本质是为了在进行读操作时代替加锁,减少加锁带来的负担。写操作使用记录的最新版本,读操作使用记录的历史版本,这样使不同事务的读-写、写-读操作可以并发执行,提高数据库并发性能。

MVCC是通过保存数据在某个时间点的快照(Read View)来进行控制的。同一个数据记录可以拥有多个不同的版本,并通过聚簇索引记录和undo日志的roll_pointer属性串联成一个记录的版本链,通过生成的快照来判断记录的某个版本的可见性。在查询时通过添加相对应的约束条件,获取用户想要的对应版本的数据。

MVCC只适用于MySQL隔离级别中的READ COMMITTED(提交读)和REPEATABLE READ(可重复读)级别。MVCC其实就是使用这两种隔离级别的事务执行普通的读操作时访问记录的版本链的过程。

1. MVCC与四种隔离级别的关系

1) READ UNCOMMITTED(未提交读)

由于存在脏读,即能读到未提交事务的数据行,所以不适用MVCC。

2) SERIALIZABLE(序列化)

由于InnoDB会对所涉及的表加锁,并非行级锁,不存在行的版本控制问题,所以也不适用MVCC。

3) READ COMMITTED(提交读)

每次读取数据时都生成一个快照,更新旧的快照,保证能读取到其他事务已经提交的内容。

4) REPEATABLE READ(可重复读)

只在第一次读取数据时生成一个快照,以后不会再更新,后续所有的读操作都是复用这个快照,可以保证每次读操作的一致性。

由此可见,虽然REPEATABLE READ(可重复读)比READ COMMITTED(提交读)隔离级别高,但是开销反而相对少,因为不用频繁更新快照。

2. 两种读取数据记录的方式

1) 当前读

读取当前数据的最新版本,而且读取到这个数据之后会对这个数据加锁,防止别的事务更改。在进行写操作时就需要进行“当前读”,读取数据记录的最新版本。

2) 快照读

其实就是读取MVCC中的快照,可以读取数据的所有版本信息,包括旧版本的信息。也就是说,“快照读”读到的不一定是数据的最新版本,有可能是之前的历史版本。

在READ COMMITTED(提交读)隔离级别下,“快照读”和“当前读”结果一样,都是读取已提交的最新版本数据。

在REPEATABLE READ(可重复读)隔离级别下,“当前读”是其他事务已经提交的最新版本数据,“快照读”是当前事务之前读到的版本,创建快照的时机决定了读到的版本。

在MySQL中,MVCC是由记录中的三个隐式列、undo日志和快照等来实现的。

02、锁机制

MySQL支持不同的存储引擎,不同存储引擎的锁定机制也是不同的。例如:MyISAM和MEMORY存储引擎只支持表级锁;InnoDB存储引擎既支持行级锁,也支持表级锁,但默认情况下采用行级锁。

1. 锁的分类

1) 按锁粒度分类

理论上,每次只锁定当前操作的数据,会得到最大的并发度,但是管理锁是很耗费资源的事情。因此,数据库系统需要在高并发响应和系统性能两方面进行平衡,这样就产生了“锁粒度”的概念。

锁粒度,即锁定的数据范围,可以衡量管理锁的开销和并发性能的关系。锁粒度越大,锁定范围越大,管理锁的开销越小,并发性越差。按锁粒度从大到小,可分为以下三种锁。

(1) 表级锁(Table-level Locking):也称表锁,用于锁定某个表。根据锁定的类型,其他用户不能向表中插入记录,甚至从中读数据也受到限制。表级锁有读锁和写锁两种类型。

表级锁的特点是开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

(2) 页级锁(Page-level Locking):用于锁定数据记录所在的某个页,是MySQL中比较独特的一种锁定级别,在其他数据库管理软件中并不常见。页是磁盘和内存之间交互的基本单位,页的大小一般为16KB。

页级锁的特点是开销和加锁时间介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般。

(3) 行级锁(Row-level Locking):也称行锁,用于锁定某行(即某条记录)。在这种情况下,只有线程使用的行是被锁定的,表中的其他行对于其他线程都是可用的,所以行级锁可以最大限度地支持并发处理。行级锁定并不是由MySQL提供的锁定机制,而是由存储引擎自己实现的,其中InnoDB的锁定机制就是行级锁定。

行级锁的特点是开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。行级锁有排他锁、共享锁和意向锁三种类型。

表级锁由数据库服务器实现,行级锁由存储引擎实现。数据锁定的范围越小,数据库的并发性越好。

2) 按对数据库操作的类型分类

事务可以对数据库进行读或写操作,按对数据库操作的类型分,可分为以下四种锁。

(1) 共享锁(Shared Lock):也叫读锁,简称S锁。事务要读取一条记录时,需要先获取该记录的共享锁。读操作不会修改记录数据,多个读操作可以同时进行,不会互相影响,多个事务可以同时给同一记录加共享锁。有了共享锁,就不能获取排他锁了。

(2) 排他锁(Exclusive Lock):也叫独占锁、写锁,简称X锁。事务要改动一条记录时,需要先获取该记录的排他锁。当前事务的写操作完成之前,它会阻断其他排他锁和共享锁。当前事务提交之后,排他锁会被释放。

(3) 意向共享锁(Intention Shared Lock):简称IS锁。当事务准备在某条记录上添加共享锁时,需要先在表级别添加一个意向共享锁。

(4) 意向排他锁(Intention Exclusive Lock):简称IX锁。当事务准备在某条记录上添加排他锁时,需要先在表级别添加一个意向排他锁。

提示

意向共享锁、意向排他锁是表级锁,MySQL设计它们的目的是在之后加表级共享锁和排他锁时,可以快速判断表中的记录是否被上锁,以避免用遍历的方式来查看表中有没有上锁的记录。表级别的这四种锁的兼容关系如表12-1所示。

■ 表12-1表级别锁的兼容关系

2. 管理InnoDB存储引擎中的锁

1) 表级别的共享锁和排他锁

(1) 设置表级锁的基本语法格式如下所示。

语法说明如下。

  • tbl_name [[AS] alias]是“表名[as 别名]”。

  • READ是给表加共享锁。

  • WRITE是给表加排他锁。

(2) 加锁完成对数据表的操作后,需要解锁,基本语法格式如下所示。

提示

InnoDB存储引擎中表级别的共享锁和排他锁只会在一些特殊情况下(例如系统崩溃恢复时)用到,在对某个表执行SELECT、INSERT、UPDATE、DELETE等语句时,InnoDB存储引擎是不会为这个表添加表级别的共享锁或排他锁的。当然,用户可以根据需要,在使用InnoDB存储引擎的表上用LOCK TABLES这样的手动锁表语句手工添加表级锁,但是应该尽量避免,因为这不但不能提供额外的保护,反而会降低并发能力。

另外,在对某个表执行诸如ALTER TABLE、DROP TABLE等的DDL语句时,其他事务在对这个表并发执行诸如SELECT、INSERT、DELETE、UPDATE等DML语句时,会发生阻塞。同理,某个事务在对某个表执行DML语句时,其他对这个表执行DDL语句的事务也会被阻塞。

这个过程是通过在服务器层使用元数据锁(MetaData Lock,MDL)来实现的,一般情况下不会使用存储引擎提供的表级别的共享锁和排他锁。

元数据锁由于篇幅所限,在此不做介绍,请自行查阅其他资料。

【例12-11】以共享锁的方式锁定bank数据库中的账户表accounts。

(1) 给账户表accounts加共享锁。

(2) 查询账户表accounts的数据。

可以查询到账户表accounts里的所有记录,说明给表加共享锁之后,可以对表进行正常的读操作。

(3) 删除表的一条记录。

此时删除记录出错,提示错误信息:[Err] 1099 - Table ‘accounts’ was locked with a READ lock and can’t be updated,说明在加共享锁后,无法对表进行删除操作。

(4) 保持现有会话窗口不关闭,在一个新的会话窗口中查询账户表accounts的数据。

可以在新的会话窗口中查询到账户表accounts中的所有记录,说明共享锁可以与其他会话兼容。

(5) 继续在这个新会话窗口添加一条插入语句。

从执行结果可以看到,该语句一直处于“处理中”的等待状态,没有结果显示。因为账户表accounts加了共享锁,其他用户是不可以对其进行写操作的。

(6) 在之前的会话窗口输入解锁语句。

从执行结果可以看到,账户表accounts的共享锁解除之后,插入语句马上执行成功,可用查询语句查询到新增的记录,只是这个插入语句的执行时间为等待时间与语句的执行时间之和。

2) 行级别的共享锁和排他锁

当用户对InnoDB存储引擎的表执行INSERT、UPDATE、DELETE等写操作前,存储引擎会自动为相关记录添加行级排他锁。语句执行完毕时,存储引擎再自动为其解锁。

但对于普通的SELECT语句,InnoDB存储引擎是不会自动加锁的。若要保证当前事务中查询出的数据不会被其他事务更新或删除,避免出现脏读、不可重复读、幻读等一致性问题,需要为查询操作显式地添加行级别的共享锁和排他锁。

(1) 在查询语句中设置行级共享锁,基本语法格式如下所示。

语法说明如下。

  • FOR SHARE表示查询时添加行级共享锁,后面可以跟NOWAIT | SKIP LOCKED,这两个参数是MySQL 8.0的新特性。

  • NOWAIT是可选选项,表示使FOR SHARE或FOR UPDATE查询立即执行,如果由于另一个事务持有的锁而无法获取行锁,则返回错误。

  • SKIP LOCKED是可选选项,表示立即执行FOR SHARE或FOR UPDATE查询,结果集中不包括由另一个事务锁定的行。

  • LOCK IN SHARE MODE也表示在查询时添加行级共享锁,与FOR SHARE功能相同。

(2) 在查询语句中设置行级排他锁,基本语法格式如下所示。

语法说明:FOR UPDATE表示在查询时添加行级排他锁,后面可以跟NOWAIT | SKIP LOCKED参数,含义同上。

提示

上述行级锁的生命周期非常短暂,可以通过手动开启事务来延长行级锁的生命周期,事务中行级锁的生命周期从加锁开始,直到事务提交或回滚才结束。

【例12-12】在bank数据库中的账户表accounts上添加行级锁。

(1) 打开两个会话窗口,并都切换到bank数据库。

(2) 在会话窗口1中,为accounts表中id值为1的行添加排他锁。

(3) 在会话窗口2中,输入下面代码。

执行上述代码后,可以正常查询账户A的信息。

(4) 在会话窗口2继续输入下面的SQL语句。

执行上述代码后,一直在处理中,没有结果显示,进入排他锁等待状态。等待一段时间后,会显示“[Err]1205 -Lock wait timeout exceeded; try restarting transaction”的锁等待超时提示。

如果在会话窗口2等待的时间内,在会话窗口1输入“ROLLBACK;”命令,则会话窗口2会马上执行成功。

(5) 在会话窗口2中输入“ROLLBACK;”语句或“COMMIT;”语句结束事务。

提示

行级锁只适用于InnoDB存储引擎,如果表不是InnoDB存储引擎,可以使用“ALTER TABLE tablename ENGINE = 存储引擎名称;”语句进行更改。当然,在数据量很庞大的实际生产环境中,最好不要随便更改存储引擎。

可以使用下面语句查看表的存储引擎,执行结果如图12-2所示。

■ 图12-2查看表的存储引擎

3. InnoDB中常用的行级锁类型

InnoDB存储引擎常用的行级锁类型有如下三种。

(1) Record Lock:记录锁,只对记录本身加锁,通过对索引行加锁实现。即使一张表没有定义任何索引,记录锁也会锁定索引记录。如果表在建立的时候没有设置任何一个索引,InnoDB存储引擎会使用隐式的主键来进行锁定。

(2) Gap Lock:间隙锁,用于锁住记录间的间隙,防止别的事务向该间隙插入新记录,针对REPEATABLE READ(可重复读)事务隔离级别而设置,可以最大限度防止幻读现象发生。

(3) Next-key Lock:Record Lock和Gap Lock的结合体,既保护记录本身,也防止别的事务向该间隙插入新记录。InnoDB存储引擎对于行的查询都采用这种锁定方式。

4. 查看事务加锁情况

在InnoDB存储引擎中,可以用以下方法,查看事务的加锁情况。

(1) 在MySQL控制台下使用如下语句。

 

此命令输出的信息量非常大,分为多段输出,每一段对应InnoDB存储引擎不同部分的信息,可以让用户了解InnoDB存储引擎的运行状态,对于开发和维护人员有很大的利用价值,尤其是在进行死锁分析和性能调优时。

其中的TRANSACTIONS部分是关于事务的统计信息,但只用这个语句还无法显示到底哪个事务对哪些记录加了哪些锁。可以先将系统变量innodb_status_output_locks设置为ON,再运行此命令,SQL语句运行如下。

以例12-12的事务为例,TRANSACTIONS部分输出如下。

 

这样,哪个事务为哪些记录加了哪些锁,就显示得很清楚了。部分输出分析如下。

① RECORD LOCKS space id 27 page no 4 n bits 72 index PRIMARY of table 'bank1'.'accounts' trx id 3859 lock_mode X locks rec but not gap waiting

这里的输出表示一个锁结构,space id是27,page no是4,n_bits属性值为72,对应的索引为聚簇索引PRIMARY,存放的锁类型是X型记录锁(排他锁)。这条语句后面的输出是加锁记录的详细信息。

② TABLE LOCK table 'bank1'.'accounts' trx id 3859 lock modeIX

这里的输出表示id为3859的事务对bank数据库中的accounts表加了表级别的意向排他锁。

(2) 可以通过系统数据库information_schema中的INNODB_TRX表查看当前正在执行的事务信息,部分输出如图12-3所示。

■ 图12-3INNODB_TRX表的部分输出

从上面的输出可以看到事务的id、状态、开始时间、隔离级别等信息。其中trx_tables_locked表示该事务加了多少个表级锁,trx_rows_locked表示加了多少个行级锁,trx_lock_structs表示该事务生成了多少个内存中的锁结构。

5. 死锁

死锁(Dead Lock)是指两个或两个以上的进程需要使用相同的数据,在执行过程中,一直处于等待对方释放资源的状态,若无外力作用,它们将一直处于等待状态,这样就产生了死锁。

MySQL检测到死锁时,会选择一个较小的事务进行回滚,并提示错误信息:[Err] 1213 -Deadlock found when trying to get lock; try restarting transaction。

提示:所谓较小的事务是指在事务执行过程中受影响的记录条数较少的事务。

在MySQL 8.0中,如果获取不到锁,添加NOWAIT、SKIP LOCKED参数会跳过锁等待,或跳过锁定。

可以使用“SHOW ENGINE INNODB STATUS \G”语句查看最近发生的一次死锁信息。如果死锁频繁发生,可以将全局系统变量innodb_print_all_deadlocks设置为ON,将每次死锁发生时的信息都记录在MySQL的错误日志中,这样就可以通过查看错误日志来分析更多的死锁情况。

 

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

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

相关文章

Golang 【basic_leaming】数组

阅读目录Array(数组)数组定义数组的初始化方法一方法二方法三数组的遍历数组是值类型多维数组二维数组的定义二维数组的遍历数组练习题1、请求出一个数组的和以及平均值 for-range2、请求出一个数组的最大值,并得到对应的下标3、从数组 [1, 3, 5, 7, 8] 中找出和为 …

探花交友_第10章_搭建后台系统(新版)

探花交友_第10章_搭建后台系统(新版) 文章目录探花交友_第10章_搭建后台系统(新版)1.1 概述1.2 API网关1.2.1 搭建网关依赖引导类跨域问题配置类配置文件测试1.2.2 配置鉴权管理器1.3 Nacos配置中心1.3.1 添加依赖1.3.2 添加boots…

33.数据统计

数据统计 后台系统首页中,显示各种统计数据,比如:累计用户数、新增用户数、登录次数等内容。 解决方案 数据库表分析 一、数据采集 需求: 1、探花系统将用户操作日志写入RabbitMQ 2、管理后台获取最新消息,构造日…

SpringBoot+微信小程序实现的云音乐小程序系统 附带详细运行指导视频

文章目录一、项目演示二、项目介绍三、项目运行截图四、主要代码一、项目演示 项目演示地址: 视频地址 二、项目介绍 项目描述:这是一个基于SpringBoot微信小程序框架开发的云音乐微信小程序系统。首先,这是一个前后端分离的项目&#xff…

C语言百日刷题第十五天

前言 今天是刷题第15天,放弃不难,但坚持一定很酷~ 再刷一套模拟题 C语言百日刷题第十五天前言一、选择题二、判断题三、多选题四、填空题五、分析程序题一、选择题 1.下列选项中,不属于开发一个C语言应用程序的具体实现步骤的是&#xf…

为什么网络应用程序是今年的主要攻击媒介之一

网络犯罪分子在绕过最新的网络应用程序防火墙方面的独创性正在将互联网应用程序变成今年增长最快的攻击媒介。面向公众的 Web 应用程序现在是渗透组织边界的最广泛使用的攻击媒介。 根据卡巴斯基全球应急响应团队最近的一份报告,始于 Web 应用程序的攻击从 2020 年…

ocker高级篇1-dockeran安装mysql主从复制

大家好,咱们前面通过十篇的文章介绍了docker的基础篇,从本篇开始,咱们的《docker学习系列》将要进入到高级篇阶段(基础篇大家可以查看之前发布的文章)。 咱们先来介绍:docker复杂方式安装软件。通过按照mysql\redis两个案例来讲解…

XC6SLX100-3FGG484C规格、XC7A15T-2CPG236I产品概述及应用

Spartan-6系列提供领先的系统集成能力,为大批量应用提供最低的总成本。这个由13个成员组成的家族扩展了逻辑单元的密度,从3840个扩展到147443个,功耗仅为之前斯巴达家族的一半,并且具有更快、更全面的连接。 Spartan-6系列基于成熟…

拯救动画卡顿之FLIP

前置知识 什么是FPS FPS是浏览器的每秒的渲染帧数,也就是浏览器切换画面的次数,大多数设备的刷新率都是60FPS,一般来说FPS越低页面就会越卡顿。 什么是像素管道? 像素管道是浏览器单个帧的渲染流水线,如果其中有某…

vue数据双向绑定

5.Vue数据双向绑定 5.1.什么是双向数据绑定 Vue.js 是一个 MVVM 框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是 Vue.js 的精髓之处了。 值得…

[ MessAuto ]: 短信验证码自动填充,理论支持所有浏览器或 APP, Only For Mac

MessAuto 开源地址:https://github.com/LeeeSe/MessAuto MessAuto 是一款 macOS 平台 自动提取 短信验证码并 粘贴回车 的软件,百分百由Rust开发,适用于任何APP。 特点: 轻量:程序占用存储 1.8 M,占用内…

NLP学习笔记(三) GRU基本介绍

大家好,我是半虹,这篇文章来讲门控循环单元 (Gated Recurrent Unit, GRU) 文章行文思路如下: 首先通过长短期记忆网络引出为什么需要门控循环单元然后介绍门控循环单元的核心思想与运作方式最后通过简洁的代码深入理解门控循环单元的运作方…

奇舞周刊 476 期:代码在内存中的 “形状”

记得点击文章末尾的“ 阅读原文 ”查看哟~下面先一起看下本期周刊 摘要 吧~奇舞推荐■ ■ ■代码在内存中的 “形状”众所周知,js 的基本数据类型有 number、string、boolean、null、undefined 等。那么问题来了 typeof null 和 typeof undefined 分别是什么呢&…

[附源码]Node.js计算机毕业设计果蔬预约种植管理系统Express

项目运行 环境配置: Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境:最好是Nodejs最新版,我…

[内网渗透]—NTLM网络认证及NTLM-Relay攻击

NTML网络认证 Windows认证分为本地认证和网络认证,当我们开机登录用户账户时,就需要将lsass.exe进程转换的明文密码hash与 sam文件进行比对,这种方式即为——本地认证 而当我们访问同一局域网的一台主机上的SMB共享时,需要提供凭证通过验证才能访问,这个过程就会设计win…

【C++】list 的模拟实现

​🌠 作者:阿亮joy. 🎆专栏:《吃透西嘎嘎》 🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 目录👉前言&…

Halcon条码和二维码质量评级

现在各行各业的人们都使用条码/二维码从生产阶段到销售点全程追踪他们 的产品。那么怎么验证生产出来的具有可读性,码的质量等级如何呢? 其实ISO行业标准已经给出了如何评估码的质量等级的标准,以下三种主要验证标准用于确定一维条码、二维码…

毕业设计 - 基于Java EE平台项目管理系统的设计与实现【源码+论文】

文章目录前言一、项目设计1. 模块设计2. 实现效果二、部分源码项目工程前言 今天学长向大家分享一个 java web项目: 基于Java EE平台项目管理系统的设计与实现 一、项目设计 1. 模块设计 从管理员角度看: 用户登入系统后,可以修改管理员的密码。同时具有以下功能…

最全的SpringMVC教程,终于让我找到了

1. 为啥要学 SpringMVC&#xff1f; 1.1 SpringMVC 简介 在学习 SpringMVC 之前我们先看看在使用 Servlet 的时候我们是如何处理用户请求的&#xff1a; 配置web.xml <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"http://xmln…

[附源码]Python计算机毕业设计国际美容会所管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…