论坛
潜水/灌水快乐,沉淀知识,认识更多同行。
ToB圈子
加入IT圈,遇到更多同好之人。
朋友圈
看朋友圈动态,了解ToB世界。
ToB门户
了解全球最新的ToB事件
博客
Blog
排行榜
Ranklist
文库
业界最专业的IT文库,上传资料也可以赚钱
下载
分享
Share
导读
Guide
相册
Album
记录
Doing
搜索
本版
文章
帖子
ToB圈子
用户
免费入驻
产品入驻
解决方案入驻
公司入驻
案例入驻
登录
·
注册
只需一步,快速开始
账号登录
立即注册
找回密码
用户名
Email
自动登录
找回密码
密码
登录
立即注册
首页
找靠谱产品
找解决方案
找靠谱公司
找案例
找对的人
专家智库
悬赏任务
圈子
SAAS
ToB企服应用市场:ToB评测及商务社交产业平台
»
论坛
›
数据库
›
PostgreSQL
›
【MySQL】事件?隔离级别?锁?详解MySQL并发控制机制 ...
【MySQL】事件?隔离级别?锁?详解MySQL并发控制机制
九天猎人
金牌会员
|
2024-8-31 20:44:46
|
显示全部楼层
|
阅读模式
楼主
主题
873
|
帖子
873
|
积分
2619
目录
1.先理清一下概念
2.锁
2.1.分类
2.2.表锁
2.3.行锁(MVCC)
2.4.如何进行事件间数据的欺压同步
2.5.间隙锁
2.6.行锁变表锁
2.7.欺压锁行
1.先理清一下概念
所谓并发控制指的是在对数据库进行并发操作时如何包管数据的一致性和精确性。在数据库中与并发控制相关的概念有如下几个:
事件
隔离界别
锁
这几个概念大家应该都知道,但是我猜许多人没有把它们串在一起搞明白他们之间的关系,导致这三个概念各是各的,造成影象负担,末了对整个数据库并发控制的体系也云里雾里的。
锁与事件的关系:
在计算机科学中,做并发控制都是用的“标志位”来实现的,说直白一点就是锁,我们基本上可以说计算机科学中并发控制的底层都是锁的头脑。在数据库中也不例外,也是通过锁来实现并发控制的。使用上锁之后,整个数据库的读写都会对外呈现出一些特质,这些特质就是事件(ACID),原子性、一致性、隔离性、长期性。
锁与隔离级别的关系:
当然锁有许多,在数据库中有行锁、表锁、读锁、写锁等等......不同级别的锁,ACID这些特质的强弱不同,这个强弱的级别就是“隔离级别”。
所以综合起来说就是用锁来实现并发控制,对外会呈现出事件(ACID),锁的级别的不同,ACID的强弱也不同,隔离级别对应也不同。
三个东西的关系理清楚后,来回顾一下事件和隔离级别的具体内容。
事件:
事件是为了包管SQL之间不产生脏数据。innodb中默认没有被包裹在事件中的一个单条SQL就是一个事件。事件是一类特性的总称,合起来为ACID:
原子性 (Atomicity):一个事件是一个不可分割的工作单元;事件中的所有操作要么全部成功执行,要么全部不执行。如果事件中的任何部分失败,则整个事件将被回滚到事件开始前的状态。
一致性 (Consistency):在事件开始和竣事时,数据库都必须处于一致状态。这意味着事件的执行不会违背任何数据库约束或规则,并且会保持业务逻辑上的一致性。一旦事件完成,它应该使数据库从一个有效状态变为另一个有效状态。
隔离性 (Isolation):并发执行的多个事件之间互不干扰,犹如它们是按顺序独立执行一样。这防止了脏读(读取未提交的数据)、不可重复读(在同一事件内多次读取同一数据时结果不同)和幻读(在事件中多次执行雷同的查询时,由于其他已提交事件的插入或删除操作导致结果集发生变革)等现象。
长期性 (Durability):当事件成功提交后,其对数据库所做的修改将会永世保存,纵然系统发生故障(如崩溃、重启等)也不会丢失这些修改。长期性通常是通过日志记录和恢复机制来包管的。
隔离级别:
事件内具有原子性,但是事件间不具有原子性,并发情况下,多事件间仍然会存在脏数据的题目。
1、脏读:事件A读取了事件B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。
2、不可重复读:事件 A 多次读取同一数据,事件 B 在事件A多次读取的过程中,对数据作了更新并提交,导致事件A多次读取同一数据时,结果 不一致。
3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时间插入了一条具体分数的记录,当系统管理员A改竣事后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
隔离级别就是为了包管事件之间不产生脏数据。
2.锁
2.1.分类
按照对数据的操作类型分类,分为:读锁、写锁。
按照对数据操作的粒度分类,分为:行锁、表锁、
表锁:
开销小、加锁快,无死锁,锁的粒度大,发生锁辩论的概率最高,并发度最低。
读锁:
又叫共享锁,针对同一份数据,多个读操作可以同时进行而不互相影响。针对被锁表,所有客户端都可以进行读操作,所有客户端都无法进行写操作,加锁方和其他客户端的区别是,加锁方直接不答应进行写操作,而其他客户端的写操作答应进行,只是会被阻塞挂起。锁解开后,所有挂起的操作线程会去重新争抢资源。
写锁:
又叫排它锁,当前写操作没有完成前,它会阻断其他写锁和读锁。针对被锁表,加锁方可以
读
写,其他客户端不可。其他客户端的写操作会直接失败,读操作会被阻塞挂起,解锁以后,被挂起的线程会重新去争抢资源。
保护机制:
读锁、写锁中,加锁方都只能读当前被自己锁定的表,这是MySQL的一个保护机制,为的就是欺压要求加锁方给出一个说法,到底准备锁多久,不给说法不让走。
MySQL中不同引擎支持不同级别的锁,myIsam支持表锁,innodb支持行锁。
2.2.表锁
表锁,我们当然是要基于使用表锁的存储引擎来聊,也就是基于myIsam引擎。
myIsam引擎中的读写锁是主动加的。
myIsam引擎在解锁后的阻塞队列中进行读写锁调理是写优先,这样一旦阻塞队列中大量都是写操作,那么读操作会很难得到锁,变得很慢,从而造成永世堵塞。
当然除了主动加锁,表锁可以通过指令来加锁。
查看所有锁:
show open tables
复制代码
解锁:
解铃还须系铃人,只有加锁方能解锁。
unlock tables
复制代码
加读锁:
lock table 表名 read
复制代码
加写锁
lock table 表名 write
复制代码
2.3.行锁(MVCC)
行锁,我们当然是要基于使用行锁的存储引擎来聊,也就是基于innodb引擎。innodb和myIsam最大的不同有两点,一是支持事件,二是接纳了行级锁。innodb下读写都是主动加行锁,这没有什么好说的。但是行锁因为粒度太细了,会影响效率的,innodb没有傻傻的只用了行锁,还给出了行锁的优化方案——MVCC。
MVCC,多版本并发控制,本质上就是使用行锁锁定数据。
对于锁的实现方式来说无非就两种
悲观锁: 基于锁的并发控制,以为数据大概率会存在并发题目,所以进行数据更改前先给要操作的数据加上锁。程序员B开始修改数据时,给这些数据加上锁,程序员A这时再读,就发现读取不了,处于等待情况,只能等B操作完才能读数据,这包管A不会读到一个不一致的数据,但是这个会影响程序的运行效率。
乐观锁:基于版本号的并发控制,以为数据大概率不会存在并发题目,所以在进行数据操作的时间不加锁,而是在提交修改操作的时间通过版本号来确定数据有没有被第三方动过。
对于行级锁这种粒度这么细的锁,选用悲观锁性能肯定是不佳的,所以mvcc其实选用的都是乐观锁。
举个例子:
当使用mysql的innodb模式的时间,在mvcc的机制下,当事件A读取了表a的快照,在事件A提交前事件B又去读取了表a并且修改了数据,接下来事件A提交时会有什么效果,直接失败回滚事件还是?
在这种情况下:
事件A提交时,InnoDB会查抄事件A对数据进行更新时的数据版本是否与事件A最初读取数据时的版本一致。如果事件B修改的数据行与事件A无关,那么事件A可以正常提交,因为它们操作的是不同的数据行。
如果事件B修改的数据行恰好是事件A准备更新的那部分数据,由于事件A处于可重复读隔离级别,它看到的是先前的版本,不会看到事件B的修改。当事件A实验提交时,InnoDB的事件处理机制会确保事件的一致性,通常有两种可能的结果:
a. 如果InnoDB检测到事件A试图更新的数据已经被事件B更新过(即版本辩论),事件A的更新操作可能会导致一个死锁错误(Deadlock),在这种情况下,InnoDB会选择回滚此中一个事件以解决死锁题目,通常会回滚较晚开始或者较晚修改数据的事件(在这里可能是事件A)。
b. 如果InnoDB的并发控制机制足够强大(比方使用Next-Key Locks来防止幻读),事件A在更新数据时就已经被制止,也就是说事件A在实验更新数据时就会被阻塞,直到事件B完成并释放锁,事件A才能继承,进而根据实际情况决定是成功提交还是因数据已改变而回滚。
2.4.如何进行事件间数据的欺压同步
MySQL的MVCC是在提交的时间才比对数据是否又修改,那么有没有办法让所有事件间的数据都是欺压同步的喃?有!通过关闭主动提交改为手动提交来包管修改的顺序性。
数据库默认开启主动提交,通过set autocommit=0可以关闭主动提交。
关闭后每次执行sql以后,通过commit命令来手动提交,才会对数据库产生影响,否则只会对当前操作方的数据快照有影响。
innodb引擎中,其他客户端想查看到最新的数据情况也必须通过commit指令来做一次同步(因为innodb默认隔离级别为可重复读)。
当一个客户端修改某行数据,未commit前,其他客户端对该行数据的修改会阻塞挂起,直到先改谁人用户commit为止。
2.5.间隙锁
使用范围条件匹配时,innodb会给符合条件的已有数据记录的索引加“范围锁”(范围锁是特别的行锁),对于键值在条件范围内但并不存在的记录,叫做间隙(GAP),innodb也会对这个间隙加锁,这种机制叫做“间隙锁”
2.6.行锁变表锁
任何需要全表扫描的情况时,行锁都会升级为表锁。
因为MySQL不知道到底该锁哪行,所以会将整个表都锁起来,然后再进行全表扫描。
全表扫描的情况无非两种:
没建索引。
索引失效。
2.7.欺压锁行
通过 for update 可以在无update操作下,欺压锁定一行。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
本帖子中包含更多资源
您需要
登录
才可以下载或查看,没有账号?
立即注册
x
回复
使用道具
举报
0 个回复
倒序浏览
返回列表
快速回复
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
or
立即注册
本版积分规则
发表回复
回帖并转播
回帖后跳转到最后一页
发新帖
回复
九天猎人
金牌会员
这个人很懒什么都没写!
楼主热帖
从洞察到决策,一文解读标签画像体系建 ...
袋鼠云平台代码规范化编译部署的提效性 ...
SpringBoot(八) - 统一数据返回,统一 ...
C# 使用流读取大型TXT文本文件 ...
微服务(三)之负载均衡(服务端和客户端) ...
JVM
打穿你的内网之三层内网渗透 ...
Flink的API分层、架构与组件原理、并行 ...
SQL中的排座位问题
MySQL中USER()和CURRENT_USER()的区别 ...
标签云
挺好的
服务器
快速回复
返回顶部
返回列表