数据库系列:InnoDB下实现高并发控制

1 介绍

并发控制是为了防止多用户并发使用数据库时造成数据错误和程序运行错误,保证数据的完整性。当多个事务并发地存取数据库时,就会产生同时读取和/或修改同一数据的情况。若对并发操作不加控制就可能会存取和存储不正确的数据,破坏数据库的一致性(Consistency)。因此,数据库中间件必须提供并发控制(Concurrency Control)机制能力,而MySQL的InnoDB引擎,很好的支持了这一块。

2 InnoDB并发控制

MySQL 是一个流行的关系型数据库管理系统,它支持多用户并发访问。并发控制是确保数据库一致性和完整性的重要机制。在 MySQL 中,有几种方法可以实施并发控制:

  • 读写锁(Read-Write Locks):MySQL 使用了读写锁来控制对数据的并发访问。读写锁是共享的,多个客户端可以同时持有读锁,但只有一个客户端可以持有写锁。当一个客户端获得写锁时,其他客户端无法获得读锁或写锁,直到写锁被释放。

  • 事务隔离级别 :MySQL 提供了不同的事务隔离级别,包括读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。较低的隔离级别允许更多的并发访问,但可能导致数据不一致;较高的隔离级别可以确保数据一致性,但会限制并发访问。

  • 锁等待和死锁:MySQL 提供了锁等待和死锁检测机制。当一个事务尝试获取一个已经被其他事务持有的锁时,MySQL 会阻塞等待,直到锁被释放。如果事务之间形成死锁,MySQL 会检测到并终止其中一个事务以解除死锁。

  • 分段锁定(Segmented Locking):MySQL 还支持分段锁定,它允许对数据库的特定部分进行锁定,而不是对整个数据库进行锁定。这对于处理大型数据集时非常有用,因为它可以减少锁定范围,提高并发性能。

  • 乐观并发控制(Optimistic Concurrency Control):MySQL 还支持乐观并发控制,它假设冲突不太可能发生,因此不会立即锁定数据。而是在更新时检查是否存在冲突,如果存在冲突,则进行适当的处理,比如回滚或重试。

  • 多版本并发控制(MVCC):MVCC允许在事务隔离级别下执行一致性读操作,以提高并发性能。

通过合理配置和使用上述机制,可以在 MySQL 中实现有效的并发控制,来保证在数据库中执行一致性和数据完整性。下面详细来说说通过并发控制保证数据一致性的常见手段:

  • 锁(Locking)

  • 数据多版本(Multi Versioning)

3 锁的基本实现

MySQL 使用锁来保持数据的一致性。在并发控制中,锁是用来防止多个事务同时对同一数据进行修改或删除,以保持数据的一致性。MySQL 中的锁机制包括共享锁和排他锁。锁的基本实现,一般是这样的:

  • 当用户对数据进行操作前,锁住,实施互斥,不允许其它任务的操作;

  • 当前操作完成后,释放锁之后,其他任务才可以执行;

但是存在一个问题,他的执行本质是串行的,无论读写,都无法并行,这样性能太差了,也不符合互联网高并发需求。于是MySQL 中的锁机制实现了共享锁和排他锁:

  • 共享锁(Shared Lock):多个事务可以同时持有共享锁,用于读取数据,但不允许修改数据。共享锁允许并发读取,提高了并发性能。

  • 排他锁(Exclusive Lock):只有一个事务可以持有排他锁,用于修改数据,不允许其他事务同时修改。排他锁会阻塞其他事务的读写操作,降低了并发性能。

简而言之就是:

共享锁之间不互斥,即读读可以并行,这样提高了数据读取的并发能力

排他锁与任何锁互斥,所以写读,写写不可以并行,其他线程的读写操作都在锁释放之后才能执行,这样对并发度是有较大影响的

所以说,单纯的锁机制,还是不满足需求,为了保证写任务没有完成之时,其他读的任务也可以并发执行,我们就需要使用另外一个能力来补充。那就是数据多版本(Multi Versioning)

4 数据多版本的实现原理

MySQL的并发控制是通过多版本并发控制(MVCC)实现的。MVCC允许在事务隔离级别下执行一致性读操作,以提高并发性能。在MySQL的MVCC中,每个数据行都有多个版本,每个版本都表示该行在不同时间点的状态。当一个事务读取数据时,它只看到该事务开始之前存在的数据版本,而不是当前最新的数据版本。这种方式允许并发读取多个数据版本,而不会相互阻塞,进一步提高并发的效果。详细拆分开来,读写同步执行的原理是这样的:

  • 执行写任务发时,Clone一份数据,打上新的版本号,与原版本号区分

  • 写任务实际操作的是克隆那个版本的数据,直至操作并提交完成后

  • 读任务可以并发执行,持续读取,读的是原版本的数据,并不会造成阻塞

image

如图所示,可以分成这几个步骤去解读:

  1. 初始数据版本为V1.0

  2. T1发起了一个写任务,这时候把数据clone了一份,进行修改,版本变为V2.0,这时候修改进行中,任务还未完成

  3. T2并发了一个读任务,依然读的是V1.0版本的数据

  4. T3又并发了一个读任务,依然不会阻塞,读的还是V1.0的版本

  5. 这时候数据修改,V1.0的数据变为V2.0的数据

  6. T4这时候发起的度任务,读到的就是V2.0的数据了

从这边可以看出,数据多版本,读写之间不需要阻塞,能够极大提高任务的并发能力。

  • 普通意义上的锁机制,本质是串行执行,效率十分低下

  • 读写锁,可以实现读读并发,但是写读依然是互斥的,也不符合互联网的机制

  • 数据多版本(Multi Versioning),才是实现读写并发的要素

5 MySQL 数据多版本的相关实现

5.1 概念介绍

在MySQL的InnoDB存储引擎中,使用MVCC(多版本并发控制,Multiversion Concurrency Control)实现多版本控制。MVCC的实现主要基于undo日志、redo日志、rollback segment 回滚存储区间、和read view。undo日志用于回滚操作,而read view用于生成数据行的历史版本。通过这种方式,InnoDB实现了非阻塞的一致性读操作。

  • redo日志数据库事务提交后,必须将更新的数据刷到磁盘上,以保证ACID特性。磁盘随机写性能较低,且过度频繁的刷盘,会极大影响数据库的吞吐量。优化方式是将修改行为先写到redo日志里,这样随机就变成了有序性,再按照时间周期将数据持久化到磁盘上,极大提高了性能。另外一方面,即使数据库崩溃,恢复之后也可以从redo日志里面获取操作Log,重新提交事务操作,然后刷盘,最终保证数据的一致性。

  • undo日志数据库事务未提交时,会将事务修改数据的Mirror Data(修改前的版本 )存放到 Undo Log中,它的主要作用是在事务执行过程中,如果发生错误或者需要回滚操作,可以通过Undo Log中的记录来撤销已经执行的操作,恢复数据到事务开始之前的状态。另外一方面,数据库奔溃时,也可以使用undo日志,撤销未提交事务,保证事务的ACID特性。

  • insert操作:undo日志存储新数据的PK(ROW_ID),回滚时执行删除即可。

  • delete/update操作:undo日志存储旧数据row(整行数据),回滚时直接恢复。

  • rollback segmentRollback Segment(回滚存储区)是数据库中的一部分存储空间,用于临时保存当数据库数据发生改变时的先前值。它主要有两个作用:

  • 通过Rollback操作来取消数据操作,使之恢复到改变之前的原始值,在transaction的过程才有效。如果执行了commit命令,那么Rollback Segment里面的值就会标识为失效,数据的改变将永久化。

  • select读取的同时另一个事务也在修改这个表的值,那么select出来的数据是修改前的值,因为修改之前的原数据存入到了Rollback Segment中,所以不会被阻塞到。

5.2 示例说明

5.2.1 初始数据

# 表结构
t_userinfo(id PK, name, sex, age);

# 默认数据
1,Brand,0,22
2,Helenlyn,1,19
3,Sol,0,21

image

先初始化一个默认的表,里面模拟几条数据。此时没有任何的事务未提交操作,所以回滚段是空的,如上图。

5.2.2 事务操作示例

start transaction;
delete from t_userinfo where id = 1;
update t_userinfo set name = 'Helenlyn...' where id = 2;
insert  into t_userinfo(name, sex, age) valus ('Lili', 1, 18);

还未执行commit 或者 rollback,所以事务处于未提交的状态

image

综上,我们可以看出Commit之前我们进行如下操作:

  • 正式提交删除前,id=1的数据作为旧版本的数据,进入了回滚存储区;

  • 正式提交修改前,id=2的数据作为旧版本的数据,进入了回滚存储区;

  • 新插入的数据 ('Lili', 1, 18), id= 4,在正式提交之前,也进入了回滚段;

我们上面说了,不是所有的操作最终都会commit,如果失败,事务rollback,就可以通过回滚存储区中的undo日志对操作进行回滚。

如果成功commit,则整体提交成功了

image

可以看到:

  • id=1 数据删除成功;

  • id=2 字段更新成功;

  • id=4 数据行插入成功;

  • 回滚存储区相关日志清掉

如果失败并执行rollback,则全部回滚

image

  • 数据删除的恢复了

  • 被修改的旧数据也恢复

  • 新增写入的数据删除

  • 回滚存储区相关日志清掉

6 总结

  • MySQL实现并发控制,保证数据一致性的方法有锁,数据多版本等

  • 普通锁串行,读写锁读读并行,Multi Versioning 读写并行;

  • redo日志保证已提交事务的ACID特性, undo日志用来回滚未提交的事务,rollback segment 为临时回滚存储区;

  • InnoDB是基于多版本并发控制的存储引擎;

  • InnoDB用的多版本是快照读不加锁,所有select都是快照读,这些数据不会被修改,并发性能特别高;

文章转载自:Hello-Brand

原文链接:https://www.cnblogs.com/wzh2010/p/17794217.html

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第27集《佛法修学概要》

丁二、天乘分三:戊一、十善业。戊二、四禅定。戊三、四空定 请大家打开讲义第七十七页,这是五乘里面的第二个法门,天乘法门。 大乘佛教把我们众生生命的现象分成了三个部分:第一个部分,叫作 本来清净;第…

CSS 之 跑马灯边框

一、简介 ​ 之前有做过渐变色边框的样式,然后某天刷抖🎵,看到某个老师在讲跑马灯的样式效果,于是就自己尝试实现一下跑马灯样式的边框,虽然这种样式并不常见(基本没卵用),其使用场…

git的分支的使用,创建分支,合并分支,删除分支,合并冲突,分支管理策略,bug分支,强制删除分支

GIT | 分支 文章目录 GIT | 分支创建分支合并分支删除分支合并冲突分支管理策略bug分支强制删除分支 创建分支 查看当前本地仓库中有哪些分支 git branchHEAD所指向的分支就是当前正在工作的分支 cat .git/HEAD创建一个分支 git branch dev创建好了,但是目前还是…

Redis基础系列-哨兵模式

Redis基础系列-哨兵模式 文章目录 Redis基础系列-哨兵模式1. 引言2. 什么是哨兵模式?3. 哨兵模式的配置4. 哨兵模式的启动和验证4.1 主master宕机,看会出现什么问题4.2 重启6379主机 5. 哨兵模式的工作原理和选举原理5.1. SDown主观下线(Subj…

Vue.js轻量级框架:快速搭建可扩展的管理系统

一、前言 在项目实战开发中,尤其是大平台系统的搭建,针对不同业务场景,需要为用户多次编写用于录入、修改、展示操作的相应表单页面。一旦表单需求过多,对于开发人员来说,算是一种重复开发,甚至是繁杂的工作…

RFID技术在汽车装备中的应用:提升安全性与效率

RFID技术在汽车装备中的应用:提升安全性与效率 射频识别(RFID)技术是一种非接触式的自动识别技术,它利用射频信号及其空间耦合和传输特性,实现对目标对象的信息读写。随着汽车工业的不断发展,汽车装备的技…

开源28181协议视频平台搭建流程

最近项目中用到流媒体平台,java平台负责信令部分,c平台负责流媒体处理,找了评分比较好的开源项目 https://gitee.com/pan648540858/wvp-GB28181-pro 流媒体服务基于 c写的 https://github.com/ZLMediaKit/ZLMediaKit 说明文档:h…

ElasticSearch扫盲概念篇[ES系列] - 第500篇

历史文章(文章累计500) 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 E…

laravel异步消息队列详细攻略Supervisor队列进程管理(实战)

1、laravel配置开启队列 这里仅演示数据库队列 查看下面/config/queue.php&#xff0c;里面defult 对应的 env常量是 QUEUE_DRIVER&#xff0c;那就在 项目根目录下的.env文件修改 QUEUE_DRIVERdatabase <?phpreturn [/*|----------------------------------------------…

64位ATT汇编语言学习第一课:汇编和链接

源文件exitTest.s内容如下&#xff1a; # This is the first program .global _start .section .text _start:movq $60,%raxmovq $9,%rdisyscall源文件里边放的就是源代码&#xff0c;而我这里源代码是使用汇编语言写的&#xff0c;都是一些人类都可以阅读的字符。之后需要经过…

c语言do while循环语句

c语言do while循环语句 c语言do while循环语句 c语言do while循环语句一、do while循环语句格式二、do while 循环案例 一、do while循环语句格式 do while语句先循环后判断,条件不符合就结束循环&#xff0c;条件符合继续循环 do { 代码 } while(表达式);int main() {int a 0…

【STM32】STM32学习笔记-MPU6050简介(32)

00. 目录 文章目录 00. 目录01. MPU6050简介02. MPU6050参数03. MPU6050硬件电路04. MPU6050框图05. MPU6050常用寄存器06. 附录 01. MPU6050简介 •MPU6050是一个6轴姿态传感器&#xff0c;可以测量芯片自身X、Y、Z轴的加速度、角速度参数&#xff0c;通过数据融合&#xff0…

LLM推理部署(七):FireAttention——通过无损量化比vLLM快4倍

Mixtral作为第一个在数万亿tokens上训练的OSS模型&#xff0c;最近在人工智能社区掀起了波澜&#xff0c;它支持“混合专家”&#xff08;MoE&#xff09;&#xff0c;并且训练和推理速度非常快。 Fireworks AI是第一个托管Mixtral的平台&#xff0c;在Mixtral公开发布之前就托…

第15届蓝桥杯嵌入式省赛准备第一天总结笔记(使用STM32cubeMX创建hal库工程+点亮LED)

一.使用STM32cubeMX创建工程 1.安装芯片包 点击红圈 找到STM32G4安装最新版本 2.创建工程 点击红圈 在搜索框里搜索STM32G431RBT6&#xff0c;然后点击Start。 然后点击System Core选择RCC&#xff0c;这里是设置外部晶振引脚。 然后配置外部高速时钟为80MHz 然后我们查看电…

基于开源组件自主开发工作流引擎系统

目前基于Java语言开发的主流开源工作流引擎有osworkflow、jbpm、activiti、flowable、camunda。其中osworkflow、jbpm技术较老已经过时&#xff0c;activiti包括activiti5、activiti6、activiti7三个版本&#xff0c;flowable分开源版和商业版&#xff0c;camunda包括camunda7和…

强化学习AI构建实战 - 基于“黄金点”游戏(二)

服务端接口 为了让大家的AI可以顺利地进行游戏&#xff0c;并验证我们对策略和AI的一些实现&#xff0c;我们需要一些基础设施来帮助我们完成一些工作。这些工作包括游戏回合的控制、参与者之间的数据同步、游戏数据的储存等功能。 为了简化这些基础工作&#xff0c;以便大家…

旧路由重置新路由设置新路由设置教程|适用于PPPoE拨号

前言 前几天朋友说路由器想要重置&#xff0c;但不知道怎么弄。所以就想着只帮忙重置路由器的话&#xff0c;只能帮到一个人。但把整个过程写成图文&#xff0c;就可以帮助更多人。 本文章适合电脑小白&#xff0c;请注意每一步哦&#xff01; 注意事项 开始之前需要确认光猫…

TAX个税小知识

人&#xff1a;个人&#xff0c;非居民个人 种类&#xff1a;工资薪金&#xff0c;劳务报酬所得&#xff0c;特许使用费&#xff0c;稿酬所得 工资按月支付扣税&#xff0c;不用个人提供发票&#xff0c;有签劳动合同&#xff1b; 其他三项按月或按次扣税&#xff0c;需要开发…

TTL篇-TtlAgent的使用

接上篇&#xff0c;TTL篇-TTL的使用-CSDN博客 TtlAgent是什么 ttl使用的典型代码是如下所示&#xff0c; DataAllArgsConstructorpublic static class Bean {private String name;}Testpublic void testBean() throws InterruptedException {TransmittableThreadLocal<Be…

10、Kafka ------ 消费者组 和 消费者实例,分区 和 消费者实例 之间的分配策略

目录 消费者组 和 消费者实例★ 消费者组★ 分区 和 消费者实例★ 分配分区&#xff08;分区 和 消费者实例 之间的分配策略&#xff09;3种分配策略★ range策略★ round-robin策略 &#xff08;轮询&#xff09;★ stick策略 如何指定分配分区的策略&#xff1a; 消费者组 和…