limit实现原理 mysql_解读数据库:深入分析MySQL中事务以及MVCC的实现原理

2604ccce233ce585a2b21b9133997c6d.png

什么是事务

事务(Transaction)是由一系列对数据库中的数据进行访问与更新的操作所组成的一个程序执行单元。

在同一个事务中所进行的操作,要么都成功,要么就什么都不做。理想中的事务必须满足四大特性,这就是大名鼎鼎的ACID。

a59c4f548a7ffd99e86062505f67c1a3.png

事务的ACID特性

并不是所有的事务都满足ACID特性,比如:对于Oracle和SQL Server数据库,其默认隔离级别是Read COMMITTED,就不满足I(隔离性)的要求;对于MySQL的NDB Cluster引擎来说,不满足D(持久性)的要求。

A(Atomicity)-原子性

原子性指的是数据库事务是不可分割的一部分,只有一个事务中的所有操作都成功,这个事务才算执行成功,一旦有一个操作失败,那么其他成功的操作也必须回滚。
以转账1000元场景为例,一个转账过程就是一个事务,这个事务主要包括以下两步:
1、从A账户扣除1000元
2、将B账户中增加1000元
试想,如果第一步成功了,那么第二步失败了,那就等于A的1000元钱直接消失了,相信这是任何人都不能接受的事项,所以数据库事务才需要保证原子性。

C(Consistent)-一致性

指的是在事务开始之前和事务结束之后,数据库的完整性约束都没有被破坏,事务执行的前后都是合法的数据状态。

比如我们有一张表中有一个字段name建立了一个唯一约束,那么当我们进行事务提交或者事务回滚之后,这个name必须依然保证唯一。

I(Isolation)-隔离性

隔离性就是说每个事务之间的操作应该相互隔离,互不干扰。比如说一个事务提交之前对另一个事务不可见。

隔离是一个相对抽象而复杂的概念,比如说事务之间的隔离性我们到底要隔离到哪种程度呢?所以,针对隔离,SQL92标准定义了4种隔离级别,这个放在后面事务的隔离级别中介绍。

D(Durable)-持久性

持久性这个概念就比较容易理解了,就是说事务一旦提交成功了,那么就应该是持久的,即使是数据库重启,服务器宕机等情况发生,数据都不会丢失(当然这个不能包括因为地震等自然灾害导致的存储数据的硬盘损发生不可逆的损坏)。

事务的管理

可能很多人会说自己都感知不到MySQL的事务,其实这是因为MySQL事务是默认开启了自动提交的,因此,如果要感知到事务,我们需要关闭自动提交或者显示开启事务。

事务的自动提交

查看自动提交语句:

SHOW VARIABLES LIKE 'autocommit';-- ON表示开启了自动提交
SELECT @@autocommit;-- 1表示开启了自动提交

执行如下语句关闭自动提交:

SET autocommit='OFF';
SET @@autocommit = 0;

不过需要注意的是,这种修改方式只是在当前会话窗口生效,对其他会话窗口是不生效的,MySQL几乎所有变量设置都会分成两个级别,session(会话)和global(全局)级别,默认就是session级别。

常用的事务控制语句

  • START TRANSACTION或者BEGIN:显示的开启事务。需要注意的是在存储过程中只能用START TRANSACTION开启事务,因为存储过程本来有BEGIN…END语法,两者会冲突。
  • COMMIT:提交事务。也可以写成COMMIT WORK。
  • ROLLBACK:回滚事务。也可以写成ROLLBACK WORK。
  • SAVEPOINT identifier:自定义保存点,适用于长事务,可以回滚到我们自定义的位置。
  • RELEASE SAVEPOINT identifier:删除一定保存点,如果没有保存点的时候,会报错
  • ROLLBACK TO[SAVEPOINT] identifier:回滚到指定保存点。

COMMIT和COMMIT WORK的区别

这两个都能提交一个事务,区别就在于提交事务之后的操作,同样的还有ROLLBACK和ROLLBACK WORK,主要是通过一个变量来控制:completion_type,可以执行下面的sql来查看结果:

SHOW VARIABLES LIKE '%completion_type%';

completion_type有如下三种结果:

fd54b933cd5ec352e92ce93aead4bf50.png

举个栗子1:

SET completion_type=1; --1
begin;--2
INSERT test2 VALUES(1,'张1');--3
commit work;--4
INSERT test2 VALUES(2,'张1');--5
select * from test2;--6
rollback;--7
select * from test2;--8

第4条语句中,我们提交了一个事务,第5条语句中我们又插入了一条数据,此时第六条语句可以查询出2条数据,接下来我们回滚,语句8再去查询就会发现只剩一条数据了,因为语句6倍回滚了,我们在语句4之后并没有显示的开启一个事务,这就说明语句4自动开启了一个新的事务。

举个栗子2:

SET completion_type=2;
begin;
INSERT test2 VALUES(3,'张1');
commit work;
select * from test2;

最后一条语句返回如下结果:

4110bc4b08b3d8c67f6a69858cf49ac9.png

先提示的断开连接,然后自动重连。测试这个例子的时候用工具比如sqlyog可能会不是很明显,因为工具会自动帮忙重连,看起来就好像没断开一样,建议用命令窗口的形式测试

事务的分类

从事务的理论角度来说,我们可以把事务分为以下五大类:

扁平事务

这种是最简单也是最常用的一种事务,这种事务中的所有操作都是原子的,要么全部成功,要么什么都不做。

带有保存点的扁平事务

这种一般比较适合于长事务,事务处理到后面报错的时候,我们可以选择不全部回滚事务,而是回滚到我们自定义好的某一个保存点。如下例子:

BEGIN;
INSERT test VALUES(1,'张1');
SAVEPOINT A
INSERT test VALUES(2,'张2');
ROLLBACK TO A
COMMIT;

上面示例语句中,我么你定义了一个保存点A,然后在后面又回滚到A,这时候提交事务,那么第二条插入语句是失败的,而第一条语句是成功的。

注意:回滚到指定保存点之后,事务仍然还在活动状态,我们依然需要执行COMMIT或者ROLLBACK语句才算结束了事务

链事务

在提交一个事务之后,释放掉我们不需要的数据,将必要的数据隐式的传给下一个事务。(注意:提交事务操作和开始下一个事务操作是一个原子操作)这就意味着下一个事务能看到上一个事务的结果。

链事务可以看成带有保存点的特殊事务,他们的区别就是带有保存点的事务可以回滚到任意保存点,但是回滚之后事务仍然活跃,需要执行COMMIT或者ROLLBACK之后才结束事务,而链事务中只能回滚到最近的一个保存点(即开始事务的点)。

链事务可以通过上面的completion_type参数来实现。上文中有举例使用方法,这里就不重复举例了。

嵌套事务

嵌套事务就是说一个事务之中嵌套另一个事务,事务之间存在父子关系,子事务的提交之后并不生效,需要等到父事务提交之后才会生效。

需要注意的是MySQL原生并不支持嵌套事务,但是可以通过保存点模拟嵌套事务,只是说这么模拟的话就没有真正的嵌套事务这么灵活。

分布式事务

分布式事务通常就是在分布式环境下,多个数据库下运行不同的扁平事务。多个数据库环境下运行的扁平事务就合成了一个分布式事务。

事务的隔离级别

Read Uncommitted(未提交读)

简称RU。这种是最低的隔离级别,等于没有隔离,基本上没有数据库会使用这个级别。一个事务可以读取到其他事务未提交的数据,这种也叫做脏读。

什么是脏读?请看下面这个例子:

512ee19b9c6561592ecc038687ef3caf.png

左边是事务1,先查一次,查到id为1的数据name为张三,这时候事务2又来了,把张三改成了李四,然后事务1又进行了一次查询,查出来了name为李四,那么假如这时候事务2发生了回滚,也就是name还是张三,但是事务1却读到了李四,这就是脏读。

Read Committed(已提交读)

简称RC。一个事务只能读取到其他事务已提交的数据,就是说在一个事务里面,执行同样的查询,会出现两次不一样的结果。Oracle和SQL Server数据库默认的数据库隔离级别。这种隔离级别解决了脏读问题,但是会出现不可重复读的问题。

什么是不可重复读?还是看上面那个例子,假设事务2更新之后马上就提交,然后事务1第二次查询查出来的结果还是李四,只是这次就不算是脏读了,因为事务2提交了,这种就叫不可重复读,因为事务1中两次查询同一条数据结果不一样。

Repeatable Read(可重复读)

简称RR。这种隔离级别解决了不可重复读问题,就是说在同一个事务中,执行相同的查询,结果都是一样的,但是这种级别会出现幻读问题(InnoDB引擎例外,InnoDB引擎通过间隙锁解决了幻读问题)。

什么是幻读?请看下面这个例子:

153ecec8336ff077f44280d8a106188e.png

上面图形中,事务1进行了一个范围查询,第一次只能查出一条记录,这时候事务2来插入了一条数据,然后事务1再次执行同一个查询,这时候就能查出来两条记录,也就是多了一条,给人一种幻觉,所以称之为幻读。

说到这里,可能有人就有疑问了,因为感觉不可重复读和幻读都是读取到已提交事务的结果,好像没什么区别?确实如此,不可重复读和幻读本质上是一样的,但是不可重复读针对的是更新和删除操作,而幻读仅针对插入操作。

Serializable(串行化)

这种是隔离的最高级别,也就是说所有的事务都是串行执行的,也就不存在并发事务,脏读,可重复读和幻读问题自然也就没有了。

不同隔离级别对比

不同的隔离级别可以解决不同的问题,大致如下图:

feb80a950921eebb0dd5521c3600b7a6.png

对于未提交读和已提交读大家可能都很好理解,只要控制一个事务提交之后才能对另一个事务可见,但是对于可重复读,MySQL到底是如何实现即使一个事务已经提交了,还能对另一个事务不可见呢?这就是接下来我们要讲解的MVCC了。

事务隔离的实现方案

事务隔离的实现方案有两种,LBCC和MVCC

LBCC

LBCC,基于锁的并发控制,英文全称Based Concurrency Control。这种方案比较简单粗暴,就是一个事务去读取一条数据的时候,就上锁,不允许其他事务来操作(当然这个锁的实现也比较重要,如果我们只锁定当前一条数据依然无法解决幻读问题)。

当前读

这个概念其实很好理解,MySQL加锁之后就是当前读。假如当前事务只是加共享锁,那么其他事务就不能有排他锁,也就是不能修改数据;而假如当前事务需要加排他锁,那么其他事务就不能持有任何锁。总而言之,能加锁成功,就确保了除了当前事务之外,其他事务不会对当前数据产生影响,所以自然而然的,当前事务读取到的数据就只能是最新的,而不会是快照数据(后文MVCC会解释快照读概念)。

LBCC方案中,如果我们的业务系统是读多写少的话,这种方案就会极大影响了效率,所以我们就有了另一种解决方案:MVCC。

MVCC

MVCC,多版本的并发控制,英文全称:Multi Version Concurrency Control。就是当我们在修改数据的时候,可以为这条数据创建一个快照,后面就可以直接读取这个快照。

那么MVCC具体到底是如何实现的呢?

为了实现MVCC机制,InnoDB内部为每一行添加了两个隐藏列:DB_TRX_ID和DB_ROLL_PTR(MySQL另外还有一个隐藏列DB_ROW_ID,这是在InnoDB表没有主键的时候会用来作为主键,想详细了解可以点击这里)。

DB_TRX_ID

长度为6字节,存储了插入或更新语句的最后一个事务的事务ID。

DB_ROLL_PTR

长度为7字节,称之为:回滚指针。回滚指针指向写入回滚段的undo log记录,读取记录的时候会根据指针去读取undo log中的记录。

正因为MySQL中undo log中会维护一个历史数据记录,所以我们应该养成定期提交事务的习惯,否则回滚段会越来越大,甚至占满了表空间。

快照读

快照读是针对上文的当前读而言,指的是在RR隔离级别下,在不加锁的情况下MySQL会根据回滚指针选择从undo log记录中获取快照数据,而不总是获取最新的数据,这也就是为什么另一个事务提交了数据,在当前事务中看到的依然是另一个事务提交之前的数据。

MySQL什么时候开始读取快照

我们先看看MySQL默认隔离级别RR下的一个例子(注意,test和test2两张表一开始都是空表,均只有id和name两个字段)。

  • 场景1(事务1操作数据之后再进行第一次查询):

2dd8236ac26347a0abdf613a59a171d3.png
  • 场景2(事务1不进行任何操作,事务2先开始第一次查询)

9fb33f3f1b9726f7aa054b6b60b34925.png

通过上面两个场景中我们可以得出结论:RR隔离级别快照并不是在BEGIN就开始产生了,而是要等到事务当中的第一次查询之后才会产生快照,之后的查询就只读取这个快照数据

  • 场景3(事务2先进行一次t1表查询之后,事务1再去操作其他表t2)

01fb85de04a276c32fda39554073e97e.png

从场景3我们可以得出结论:RR隔离级别快照并不只是针对当前所查询的数据,而是针对当前MySQL中的所有数据(跨库也一样,只要在同一个MySQL)

MVCC查询机制

MVCC机制到底如何查询的呢?假设由很多个事务同时进行,那么就会产生很多快照,查询的时候又到底是怎么做的呢?

接下来我们把抽象的概念具体化,假定DB_TRX_ID和DB_ROLL_PTR均为整型,接下来我们进行查询演示:

1、清空原先的test表,事务A插入两条数据,此时DB_TRX_ID(事务id)为1,DB_ROLL_PTR(回滚指针为null)

f25badab9dca92da8bfc50b4cdccb43d.png

2、这时候事务B进行了一次查询,会得到上面的结果,事务2还没提交的时候又来了事务C,事务C插入了id=3的数据,此时表中的数据如下:

7f913132125aa09e672400a5fe7ec208.png

注意,这时候第3条数据的事务id为3,因为事务2也会产生一个事务id
3、这时候事务B再次进行查询,根据上面了解的,我们知道,这时候应该是查询不出王五的,所以实际上二次查询可能是这么查的:

select * from test where 事务id<=2-- 因为当前的事务id为2

4、假如这时候事务D又来了,把id=1的数据给删除了,这时候会把原数据的回滚指针记录为当前的事务id:4,所以此时数据如下:

c2aefd83c9aeebd92766b3ad1faf937a.png

5、回到事务B,继续查询,应该还是只有1和2两条数据,那么他可能是这么查询的:

select * from test where 事务id<=2 and (回滚指针 is null or 回滚指针 >2)

6、假如这时候又来了事务E,对第2条数据进行了更新,这时候会生产一条事务id为5的数据,并把原数据的回滚指针也同时标记为当前的事务id:5,那么会得到如下数据:

5c7379cbf4a2f5cc63156549de49f718.png

根据上面猜测,执行下面的查询:

select * from test where 事务id<=2 and (回滚指针 is null or 回滚指针 >2)

这时候发现,查出来的数据还是只有1和2两条。

MVCC查询两大规则

综上,MVCC大致查询规则如下:
1、只查询事务id小于等于当前事务id的数据。(这里要等于是因为假如自己的事务插入了一条数据,会生成一条当前事务id的数据,所以必须包含本事务自己插入的数据)
2、只查询未删除(回滚指针为空)或者回滚指针大于当前事务id的数据。(这里不能等于是因为假如自己的事务删除了一条数据,会生成数据的回滚指针为当前事务id,所以必须排除掉自己删除的数据)

当然,上面规则只是简化了,实际查询远比这里复杂,只是希望借助这种简单化的概念可以帮助大家更好的理解MVCC工作机制。

作者:双子孤狼
原文链接:https://blog.csdn.net/zwx900102/article/details/106544843

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

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

相关文章

c# 审批流引擎_小熊OA:流程引擎才能真正起到管理价值!

首先说说什么是流程管理。流程作为企业运作的基础&#xff0c;不同部门、不同客户和供应商都需要流程来进行协同运作&#xff0c;以流程带动信息、物资和资金在企业内部无障碍地流转。流程管理是一种以业务流程为中心&#xff0c;以提高组织业务绩效为目的的系统化方法。它是一…

在计算机桌面上添加小工具日历,实用桌面小工具时钟日历在win7中的添加方法...

我们在win7系统的使用中&#xff0c;小伙伴们都是知道的系统可以直接选择安装不同的小工具在电脑中使用&#xff0c;比如电脑中的时钟日历等都是可以直接安装在桌面来使用的牡丹石有小伙伴对于时钟日历不知道是在哪里添加到桌面的&#xff0c;对于这个疑问今天小编就来跟大家分…

html 为什么ul不撑开,给li设置float浮动属性之后,无法撑开外层ul的问题。

以下面代码为例&#xff0c;其实有好几种解决方法&#xff0c;我用的这种并不是最简单的。给li设置float浮动属性之后&#xff0c;无法撑开外层ul的问题。ul{border: 1px solid #000;width: 200px;height: auto;margin-top: 100px;}li{float: left;list-style: none;margin-lef…

计算机黑屏无法启动,电脑黑屏无法启动怎么办

有网友说自己的电脑黑屏无法启动&#xff0c;具体现象就是开机以后&#xff0c;主机电源灯亮&#xff0c;但显示没有任何显示。那么电脑黑屏无法启动的原因很多&#xff0c;下面小编就给大家分享下电脑不能开机黑屏的解决方法。静电影响&#xff1a;1、当出现不能开机的问题时&…

测试显卡的软件叫游戏什么,显卡测试软件哪个好

显卡测试软件哪个好3DMARK063DMark06于2006年1月17日发布&#xff0c;主要使用最新一代游戏技术衡量DirectX 9级别的3D硬件。此前的3DMark都是随着新版DirectX和新一代硬件的发布而推出&#xff0c;在一定程度上限制了3DMark对最新硬件性能的充分挖掘。现在&#xff0c;DirectX…

华润置地php面试题_长春华润置地崑崙御,以至臻匠心,成就城市典范

点击上方蓝字,记得关注我们&#xff01;长春华润置地崑崙御&#xff0c;以至臻匠心&#xff0c;成就城市典范每一次启程都是为了更好的遇见&#xff0c;每一次出发都是为了更高的追求。6月23日&#xff0c;集精工匠心所筑&#xff0c;汇万千美好所成&#xff0c;华润置地崑崙御…

数据消费过程_特色鲜卤现捞加盟店经营要如何抓准消费群体定位

唐小卤是市场上摸爬滚打了这么多年&#xff0c;认为对市场来说&#xff0c;有成功的创业者标明&#xff0c;在目前的行业中&#xff0c;谁能抓住女性消费者&#xff0c;谁就能占领更多的市场份额&#xff0c;诚然&#xff0c;女性消费者在市场里占领了重要地位&#xff0c;这在…

做形态学方法的团队_图像分割实战-分水岭分割方法和GrabCut 算法

1. 分水岭分割方法它是依赖于形态学的&#xff0c;图像的灰度等级不一样&#xff0c;如果图像的灰度等级一样的情况下怎么人为的把它造成不一样&#xff1f;可以通过距离变换实现&#xff0c;这样它们的灰度值就有了阶梯状的变换。风水岭算法常见的有三种方法&#xff1a;&…

计算机gt的使用方法,旗舰级综合效果器 BOSS GT-1000使用宝典(二) | 基础操作

原标题&#xff1a;旗舰级综合效果器 BOSS GT-1000使用宝典(二) | 基础操作在上一期的使用宝典中&#xff0c;B老板为大家介绍了GT-1000内置的前级&#xff0c;箱体及麦克风等&#xff0c;&#x1f449; GT-1000使用宝典(一) | 了解你的神器 想必各位对自己手中的神器有了比较全…

日期格式化为yyyymmdd_你还在用SimpleDateFormat格式化时间嘛

Jdk1.8之时间处理该文章已经同步到Github&#xff1a;https://github.com/stackInk/makerstack1. 传统时间处理的问题1.1 多线程环境下的SimpleDateFormat当多个线程使用同一个时间处理对象进行对日期的格式化的时候&#xff0c;会出现java.lang.NumberFormatException: multip…

存储ic载板_延伸IC领域 崇达技术拟将持有普诺威55%股权

立即加星标每天看好文PCB网城讯崇达技术7月1日公告&#xff0c;6月30日&#xff0c;崇达技术股份有限公司(以下简称“崇达技术”)与朱小红、马洪伟在公司会议室签署了《关于江苏普诺威电子股份有限公司之股份转让协议》(以下简称“协议”)。根据协议&#xff0c;公司拟以自有资…

微云服务器失败原因_梦幻西游:服务器发生异常?游戏出现明显卡顿感,正在排查问题...

就在刚刚&#xff0c;不少梦幻玩家都在讨论一个情况&#xff0c;那就是服务器出现了明显的卡顿感&#xff0c;一些商人也陆续掉线&#xff0c;难道是服务器出现了异常&#xff1f;退出游戏之后&#xff0c;一直无法进入&#xff0c;登录界面总是停留在"正在连接某某服务器…

maven多模块项目部署到服务器,GitHub - baxias/foweb: 一个基于 Spring+SpringMVC+Mybatis 的Maven多模块项目。(实现前后端分离的服务器端)...

Foweb FrameworkA multi-modules maven project base on SpringSpringMVCMybatis.一个基于 SpringSpringMVCMybatis 的Maven多模块项目。使用文档两种使用方式&#xff1a;1. 直接将项目download下来&#xff0c;然后在IDE(Eclipse或者IDEA)中以maven项目导入&#xff0c;注意这…

网站需要数据库服务器吗,网站需要独立的服务器数据库吗

网站需要独立的服务器数据库吗 内容精选换一换文档数据库服务提供使用数据管理服务(Data Admin Service&#xff0c;简称DAS)、内网和公网的连接方式。文档数据库服务默认为您开通了远程主机登录权限&#xff0c;推荐您使用更安全便捷的数据管理服务连接实例&#xff0c;具体请…

只提取单元格中的数字_提取Excel单元格中的数字(4类)及原理

文中总结了4类从包含有中文、字母、数字的单元格数据中只提取数字的公式。(使用的时候把单元格名称改为实际的单元格名称即可)。1.提取文本左侧数据当单元格中数字在左侧&#xff0c;文字内容在右侧时&#xff0c;我们可以使用一下公式来将数字快速提取出来。函数公式&#xff…

delphi 执行长时间存储过程 显示进度_项目管理_十大管理体系之「项目进度管理」知识整理及心得分享...

项目进度管理项目进度管理在项目是项目管理三大要素之一&#xff0c;在项目管理中占有非常重要的地位。往往很多项目要求进度节点是一个固定期限&#xff0c;无法修改&#xff0c;所以进度把控就显得尤为重要。什么是进度管理&#xff0c;在你写project项目计划时就非常清楚的可…

bettertouchtool闪退_BetterTouchTool for Mac 3.238 无闪退 触控板增强工具

BetterTouchTool为魔术鼠标添加了许多新的完全可自定义的手势&#xff0c;Multi-Touch MacBook触控板和Magic Trackpad。这些手势是可定制的&#xff1a;魔术鼠标&#xff1a;捏合/缩小(缩放)单指点击左边单指轻拍右键单指中间单指轻拍单指点击中间双指轻敲双指点击双指轻扫(上…

宝塔php扩展fil_宝塔面板安装Redis给WordPress网站加速优化教程

宝塔面板php安装redis缓存以加快WordPress的开启速度&#xff0c;因为WordPress打开速度慢&#xff0c;所以霜天 seo使用多种方式来提高wordpress的加载速度&#xff0c;其中一个好办法是&#xff1a;使用redis加速缓存。本文的主题是宝塔面板php安装redis缓存加速WordPress&am…

常量缓存与integer比较_Integer缓存范围到底是多少?

本文主要大致思路为&#xff1a;不管从工作中还是面试&#xff0c;这篇文章都应该好好看完&#xff0c;本人认为是非常有用的。案例Integer是基本类型int的封装类。平时不管是入坑多年的小伙伴还在入坑路上的小伙伴&#xff0c;都应该知道的使用频率是相当高。下面模仿订单支付…