详解MySQL的并发控制

news2024/11/27 10:40:26

目录

1.概述

2.事务

2.1.什么是事务

2.2.事务的隔离级别

2.2.1.三种数据一致性问题

2.2.2.四种隔离级别

2.3.如何设置隔离级别

3.锁

3.1.锁与事务的关系

3.2.分类

3.3.表锁

3.3.1.概述

3.3.2.读锁

3.3.3.写锁

3.3.4.保护机制

3.4.行锁

3.4.1.概述

3.4.2.什么是MVCC

3.4.3.mvcc的使用

3.4.4.间隙锁

3.4.5.行锁变表锁 


1.概述

所谓的并发控制,就是规避多个会话并发访问数据库带来的诸如脏数据之类的数据一致性问题,MySQL中提供了一系列的机制让我们可以去进行并发控制。

本质上来说MySQL就是用的两种锁来进行并发控制,一种是表锁,锁住整张表;一种是行锁,锁住某个数据行。

平时我们使用的时候,很少会直接去操作锁,因为MySQL已经帮我们封装的很好了,直接用innodb引擎+事务就能很好的进行并发控制,事务底层其实依赖的就是行锁。

本文会先聊事务、再聊表锁、行锁,但其实总的来说MySQL进行并发控制,就是行锁和表锁,事务的底层用的就是行锁,只是事务太重要了所以单独拎出来作为一个独立的章节聊。

2.事务

2.1.什么是事务

注意:只有innodb引擎是支持事务的,所以本文与事务相关的讨论,默认都是在innodb引擎下。

在实际使用中,会存在这样一类场景,我们希望几条SQL要么同时执行成功,要么同时失败,不能有的成功,有的失败。

比如网购下单,生成订单、扣减库存两条SQL,必须保证要么全部成功,要么全部失败,不能说生成订单成功,但是扣减库存失败了,或者说扣减库存成功但是生成订单失败了,以上任何一种情况都是会产生脏数据的。如果两者中有一者失败,另外一个也需要跟着执行不成功,从而保证数据的正确性。

事务就是为了满足将多条捆绑在一起,同成功,同失败而出现的。人们在实现事务过程中,发现事务要实现上面我们说的效果,那么就必须实现四点:

  • 原子性(Atomicity)
  • 一致性(Consistent)
  • 隔离性(Isolation)
  • 持久性(Durable)

也就是大名鼎鼎的ACID,很多地方称其为事务的四大特性。

1.原子性:

事务是一个原子操作单元,其对数据的修改,要么全部执行,要么全部不执行。

2.一致性:

数据库中的数据总是从一个状态到另一个状态,不能存在中间状态。继续以网购下单为例,一开始的数据库中的数据为A状态,执行完事务,扣减库存、新增订单后的数据状态为B状态,数据库只能由A到B,不能出现诸如扣了库存,没生成订单,或者生成了订单,没扣库存这样的中间状态。

3.隔离性:

一个事务在提交之前,其所做的修改对其它事务来说是不可见的。不保证隔离性会产生脏数据,这个很好理解,举个例子:

A的银行账户有400,有两个事务,彼此之间数据可见,也就是一个事务修改数据,不管提没提交其他事务都看得见。

事务1,A向B转200:

  • A的账户扣减200
  • B的账户新增200

事务2,A向C转200:

  • A的账户扣减200
  • C的账户新增200

如果在事务1中的1、2步的时间间隙内事务2间插执行完毕,那么在事务1第2步执行前A的账户中已经被扣减了两次200,余额为0,C的账户中多了200。

这时候如果在事务1的第2步中出错了、回滚,那么A的账户又会回到事务1第一步执行之前的状态,也就是A的账户又恢复成了400。最后C的账户平白无故多了200。

4.持久性:

事务完成后,其对数据的修改是永久的,即使系统断电、重启,也不会变。

2.2.事务的隔离级别

2.2.1.三种数据一致性问题

在没有隔离性的情况下,事物之间会出现3种数据一致性问题:

  1. 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
  2. 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
  3. 幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

2.2.2.四种隔离级别

隔离级别可理解为,隔离性的严格度,MySQL并不是固定死了各个事务间就是不可读的,而是规定了各种强度的隔离级别。

观察上面3种数据一致性问题就会发现,解决它们需要的隔离性是递增的,MySQL一共给出4种隔离级别,隔离性也是递增的,对应解决以上3个问题,有3种,加上1种3种问题都能覆盖解决的:

  1. Read Uncommitted(读未提交):最低的隔离级别,允许一个事务读取另一个事务尚未提交的数据变更。可能导致脏读(Dirty Read)问题。

  2. Read Committed(读已提交):确保一个事务只能读取另一个事务已经提交的数据变更。防止脏读问题,但可能导致不可重复读(Non-repeatable Read)问题。

  3. Repeatable Read(可重复读):确保在同一个事务中多次读取同一数据时,能够得到一致的结果。防止脏读和不可重复读问题,但可能导致幻读(Phantom Read)问题。

  4. Serializable(串行化):最高的隔离级别,强制事务串行执行,确保不会发生脏读、不可重复读和幻读问题。但是并发性能较差,通常不建议在高并发环境中使用。

2.3.如何设置隔离级别

可以在连接字符串中设置隔离级别:

jdbc:mysql://localhost/mydatabase?useSSL=false&characterEncoding=utf8&transactionIsolation=隔离级别

可以通过SQL在会话中设置隔离级别:

SET TRANSACTION ISOLATION LEVEL 隔离级别;

3.锁

3.1.锁与事务的关系

锁是计算机协调多个进程或线程并发访问某一资源的机制,用来解决并发访问带来的数据一致性问题。在数据库中,除传统的计算资源(如CPU、IO、RAM)的争用以外,数据更是会被并发访问的资源。所以MySQL数据库也用锁机制来保证数据并发访问的一致性。

不同的隔离级别底层就是用不同的锁来实现的。

3.2.分类

MySQL的锁可以从两种维度来分,

一个维度是按照锁的是一行,还是锁的是整张表,分为:

  • 行锁
  • 表锁

另一个维度是按照锁的操作是读操作,还是写操作,分为:

  • 读锁
  • 写锁

3.3.表锁

3.3.1.概述

MySQL中innodb引擎和myisam引擎均支持用lock tables指令来锁表。

3.3.2.读锁

读锁,一种共享锁,针对被锁表,所有会话都可以进行读操作,所有会话都无法进行写操作。加锁方和其他客户端的区别是,加锁方直接不允许进行写操作,而其他会话的写操作允许进行,只是会被阻塞挂起。锁解开后,所有挂起的操作线程会去重新争抢资源。

加锁指令:

lock tables 表名 read;

释放锁指令:

unlock tanles;

加锁方不允许进行写操作:

其它客户端的写操作在加锁方释放锁之前都被挂起:

3.3.3.写锁

写锁,排它锁,针对被锁表,加锁方可以读写,其他会话的写操作会直接失败,读操作会被阻塞挂起,解锁以后,被挂起的线程会重新去争抢资源。

加锁指令:

lock tables 表名 write;

其它会话的读操作、写操作在加锁方释放锁之前都被阻塞挂起:

 

3.3.4.保护机制

读锁、写锁中,加锁方都只能读当前被自己锁定的表,这是MySQL的一个保护机制,为的就是强制要求加锁方给出一个说法,到底准备锁多久,不给说法不让走。

3.4.行锁

3.4.1.概述

innodb和myIsam最大的不同有两点,一是支持事务,二是支持行级锁。

3.4.2.什么是MVCC

行锁没有显式的声明办法,而是藏在默认实现中,MVCC 是 MySQL InnoDB 存储引擎的默认并发控制机制,其采用的就是表锁。

并发控制有几种处理方法,

第一种: 基于锁的并发控制,程序员B开始修改数据时,给这些数据加上锁,程序员A这时再读,就发现读取不了,处于等待情况,只能等B操作完才能读数据,这保证A不会读到一个不一致的数据,但是这个会影响程序的运行效率。

第二种:MVCC,每个用户连接数据库时,看到的都是某一特定时刻的数据库快照,在B的事务没有提交之前,A始终读到的是某一特定时刻的数据库快照,不会读到B事务中的数据修改情况,直到B事务提交,才会读取B的修改内容。

MVCC其实就是实现事务的关键,后续会有文章专门深入聊事务的实现,此处暂不展开。

3.4.3.mvcc的使用

首先有一个需要纠正的是,很多地方都说mvcc是通过手动提交来触发的,这是个误导,不管手动提交还是自动提交MVCC机制都是生效的,只是手动提交用来观察mvcc过程更加直观。

此处为了直观,我们也以手动提交为例,首先通过set  autocommit=0可以关闭自动提交。关闭后每次执行sql以后,通过commit命令来手动提交,才会对数据库产生影响,否则只会对当前操作方的数据快照有影响。innodb引擎中,其他客户端想查看到最新的数据情况也必须通过commit指令来做一次同步(因为innodb默认隔离级别为可重复读)。

当一个会话修改某行数据,未commit前,其他会话对该行数据的修改会阻塞挂起,直到先改那个会话commit为止。

3.4.4.间隙锁

使用范围条件匹配时,innodb会给符合条件的已有数据记录的索引加“范围锁”(范围锁是特殊的行锁),对于键值在条件范围内但并不存在的记录,叫做间隙(GAP),innodb也会对这个间隙加锁,这种机制叫做“间隙锁”。

3.4.5.行锁变表锁 

任何需要全表扫描的情况时,行锁都会升级为表锁。

因为MySQL不知道到底该锁哪行,所以会将整个表都锁起来,然后再进行全表扫描。

全表扫描的情况无非两种:

  1. 没建索引。
  2. 索引失效。

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

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

相关文章

Redis Java API操作

1、普通maven工程方式 Redis不仅可以通过命令行进行操作&#xff0c;也可以通过JavaAPI操作&#xff0c;通过使用Java API来对Redis数据库中的各种数据类型操作 导入POM依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http…

【Linux Network】传输层协议——UDP

目录 传输层 端口号 端口号范围划分 认识知名端口号(Well-Know Port Number) netstat pidof UDP协议 UDP协议端格式 UDP的特点 面向数据报 UDP的缓冲区 UDP使用注意事项 基于UDP的应用层协议 UDP详解&#x1f337; 传输层 在TCP/IP协议中可以把网络简单的划分为四个部分&#…

大数据如何助力营销(3)产品定位

在市场竞争日益激烈的环境下&#xff0c;产品定位是企业成功的关键因素之一。产品定位是指根据目标市场和目标消费者的需求、偏好和期望&#xff0c;确定产品的特性、功能、形象和价值&#xff0c;并与竞争对手的产品进行差异化的过程。产品定位不仅影响产品的设计、开发、生产…

全面讲解涂鸦PaaS2.0开发平台!物联网干货预警

之前我们有介绍过涂鸦 IoT PaaS&#xff08;点击查看往期介绍&#xff09;&#xff0c;面向开发生态&#xff0c;它集成了云开发、App 开发、硬件开发三大核心支撑能力&#xff0c;能够全方位助力开发者打造极具竞争力的个性化 IoT 解决方案&#xff0c;极大地降低 IoT 开发门槛…

Appium APP自动化环境搭建

1.下载安装 F:\android-sdk-windows F:\Appium-windows-1.21.0 F:\nodejs 2.创建一个bat文件&#xff0c;命名为appium.bat&#xff0c;并在其中写入如下内容&#xff1a; node Appium安装目录\resources\app\node_modules\appium\build\lib\main.js %* 注意&#xff1a;请…

从0到1开始,一步步搭建Web自动化测试框架

测试框架的设计有两种思路&#xff0c;一种是自底向上&#xff0c;从脚本逐步演变完善成框架&#xff0c;这种适合新手了解框架的演变过程。另一种则是自顶向下&#xff0c;直接设计框架结构和选取各种问题的解决方案&#xff0c;这种适合有较多框架事件经验的人。本章和下一张…

【zabbix】批量监控端口,自动发现规则

快速搞定端口批量监控 一、脚本及配置 1、&#xff08;文件名&#xff1a;check_port.py&#xff09;&#xff08;python2.7版本&#xff09; 存在路径&#xff1a;/etc/zabbix/zabbix_agentd.d/check_port.py 这个脚本有一部分内容是我从百度上找的&#xff0c;有一部分自己…

【C++】红黑树的实现

文章目录 &#x1f4d5; 概念特性 &#x1f4d5; 红黑树具体实现节点定义结构框架插入 &#x1f4d5; 概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或Black。 通过对任何一条从根到叶子的路径上各个…

Python基础(四)

目录 一、程序的组织结构 1、前言 二、顺序结构 1、介绍 三、对象的布尔值 1、介绍 2、规定 四、分支结构 1、单分支if结构 1、语法语义 2、语法结构 3、案例 2、双分支if...else结构 1、语法语义 2、语法结构 3、案例 3、多分支if...elif...else结构 1、语…

Java语言---栈与队列

目录 一.栈 1.1栈的概念 1.2.栈的实现 1.2.1数组实现 栈 栈的创建 栈的基本方法实现 1.2.2链表实现 栈 栈的创建 栈的基本方法实现 二.队列 2.1队列的概念 2.2队列的实现 2.3代码实现 2.3.1队列代码的构建 2.3.2 队列 基础方法实现 总结 &#x1f63d;个人主页…

深入理解2D卷积和3D卷积

文章目录 卷积核的维度2D卷积单通道多通道代码example2d卷积操作后变化 3D卷积单通道多通道代码 在项目中用到了conv3但是对其背后的原理还有一些模糊的地方&#xff0c;conv2d与多通道的conv2d的区别在哪里&#xff1f;conv3d的思想理论是什么&#xff1f;对此进行探究和记录……

「AI之劫」:当机器超越人类底线,正在侵犯我们的创造力和道德

随着AI技术的不断发展&#xff0c;AI生成内容&#xff08;AIGC&#xff09;已经成为数字娱乐、商业营销和学术研究等领域的热门话题。随着人工智能技术的不断发展越来越多的领域开始应用AI技术&#xff0c;其中之一就是内容生成领域。 AIGC全称为AI-Generated Content, 指基于生…

2023年5月广州/深圳制造业产品经理很适合考的证书-NPDP

产品经理国际资格认证NPDP是新产品开发方面的认证&#xff0c;集理论、方法与实践为一体的全方位的知识体系&#xff0c;为公司组织层级进行规划、决策、执行提供良好的方法体系支撑。 【认证机构】 产品开发与管理协会&#xff08;PDMA&#xff09;成立于1979年&#xff0c;是…

【利用AI让知识体系化】入门Egg框架(含实战)

思维导图 文章目录 思维导图第一章&#xff1a;概述1.1 Egg.js 简介1.2 Egg.js 的架构和优势1.3 Egg.js 的基本组件和插件 第二章&#xff1a;环境搭建2.1 Node.js 环境安装和配置2.2 Egg.js 应用创建和项目结构介绍2.3 Egg.js 应用部署和启动 第三章&#xff1a;基本开发3.1 路…

经纬恒润新产品系列 | 这款AR-HUD将颠覆你的认知

随着科技的发展与突破&#xff0c;智能化产品在汽车领域扮演了越来越重要的角色。本文即将介绍**经纬恒润新产品——AR-HUD&#xff08;增强现实抬头显示系统&#xff09;&#xff0c;**它可以将科幻电影中的驾驶场景变为现实——将信息投影在挡风玻璃上&#xff0c;基于此功能…

开发环境搭建和创建STM32工程

目录 一、开发环境搭建 1. STM32CubeMX 2.Keil安装 二、创建STM32工程 一、开发环境搭建 1. STM32CubeMX ST公司出品 工具链接 https://www.st.com/zh/development-tools/stm32cubemx.html STM32CubeMX是一种图形工具&#xff0c;通过分步过程可以非常轻松地配置STM32微控制器和…

coolshell 镜像备份站点

缅怀技术大佬做的一个镜像站点 - RIP 消息刚开始是在推特传开&#xff0c;后面得到了家人同事的证实。噩耗&#xff01; worldpeople2019 太意外了&#xff01;中年程序员&#xff0c;感觉年龄跟我差不多&#xff0c;怎么就这么突然去世了&#xff1f;&#xff01;诸位码农朋友…

Python爬虫进阶(1),Django+Selenium+Mysql+SimpleUI,从零开始搭建自己的爬虫后台管理系统

如果爬虫做完的话都会发现每个文件要么保存到csv或者是其他格式的文件中&#xff0c;这样做多少会有些麻烦&#xff0c;所以需要将这些内容保存起来方便自己管理和查看内容。 相对于flask而言Django有着相对成熟的一个后台管理系统配合上其他一些插件就可以做到即插即用的效果…

hive安装及配置

hive安装和部署 Hive地址 1&#xff0e;Hive官网地址 http://hive.apache.org/ 2&#xff0e;文档查看地址 https://cwiki.apache.org/confluence/display/Hive/GettingStarted 3&#xff0e;下载地址 http://archive.apache.org/dist/hive/ 4&#xff0e;github地址 http…

全新版本,手把手教你配置c\c++

上一篇图片多&#xff0c;语句乱&#xff0c;内容乱 这一篇采用全新的教程 这次在不删软件的前提下进行 老规矩先把之前看的教程残余删除 如果你有很多插件和设置这边建议先备份 打开c盘&#xff0c;在搜索栏里输入你的用户名 在箭头位置搜索你的用户名&#xff0c;就是你…