首页 > 数据库 >Mysql存储引擎(InnoDB-事务原理)

Mysql存储引擎(InnoDB-事务原理)

时间:2024-12-24 22:02:52浏览次数:6  
标签:存储 隔离 级别 事务 InnoDB 提交 Mysql 数据 读取

1、什么是事务

        事务是一组命令的集合,要么全部成功,要么都不成功。事务有四个特征,即原子性、一致性、隔离性、持久性。其中隔离性又有四大隔离级别,分别是 读未提交,读已提交、可重复读、串行化,四大隔离级别主要解决三个现象,脏读,不可重复读,幻读。

 2、事务的四大特性(ACID)

        原子性(Atomicity):原子性要求事务中的命令组要么都执行成功,要么都执行失败,确保数据库数据的完整性。如果命令组中的命令发生异常,即事务发生回滚操作,将数据撤回至事务开始前的状态。

  一致性(Consistency):持久性要求事务的系统从一个持久性状态转换至另一个持久性状态,保证数据库的完整性约束。

  隔离性(Isolation):隔离性要求事务之间是独立的,互不影响。即一个事务的操作不影响其他的事务执行。隔离性可配置的隔离级别来实现,包含读未提交,读已提交,可重复度,串行化等四个隔离级别,随着隔离级别的提升,事务之间的影响会减少,但数据库性能也会随之降低。

  持久性(Durability):持久性要求事务一旦提交,对数据库的更改是永久的。就算应用系统异常/崩溃,数据也不会丢失。

3、事务隔离级别

       事务隔离级别本次会根据操作来讲解,尽可能的为大家展现这些级别的作用与解决了什么问题。

      数据库隔离级别:

  • READ UNCOMMITTED:读未提交
  • READ COMMITTED:读已提交
  • REPEATABLE READ:可重复读(默认隔离级别)
  • SERIALIZABLE:串行化

3.1、读未提交

 3.1.1、先设置隔离级别

# 设置会话的隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
# 设置全局的隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
# 查询隔离级别
SHOW VARIABLES LIKE 'transaction_isolation';

3.1.2、验证

        1、事务一中读取读取全表数据。

        2、事务二中新增一条数据,但不提交。

        3、事务一再次读取全表数据。

        可以从图中看到事务一竟然读取到了事务二没有提交的数据。 

        4、事务二回滚事务,事务一再次读取。

         事务二回滚数据查询。

        事务一再次读取:

         可以看出事务一无法获取事务二新增数据,原因:事务二事务回滚了。

        总结:从上面4个步骤与结果图中可以看出,事务一读取到了事务二未提交的数据,一旦事务二回滚,事务一读取的数据就是脏数据了,会对业务系统造成不可预料的错误。

        这上面的现象也是我们所说的脏读。

3.2、读已提交

 3.2.1、设置隔离级别

# 设置会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
# 设置全局隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
# 查询事务隔离基本
SHOW VARIABLES LIKE '%transaction_isolation%';

3.2.2、验证

注意:本次验证 解决脏读,未解决 不可重复读和幻读。

解决脏读问题:

a)事务一读取全部数据

b)事务二新增一条数据,事务一在读取全部数据。

      可以看出,事务二新增角色后,事务一并无法查询出来。那就看看C步骤。 

c)事务二提交数据,事务一在读取数据。

        可以看到,事务二提交后,事务一才会查询出来。先不着急下结论,我们看看事务二在新增一条数据然后回滚,看是否可以查出。 

d)事务二在新增一条数据,事务一读取全表数据。

        可以看出,事务一无法查出事务二未提交的数据。那事务二回滚再看看。 

e)事务二回滚数据,事务一读取全表数据。

        事务二回滚后,事务一也一样无法查询出新增数据。

        结论:读已提交隔离级别中,事务只能读取其他事务已经提交的数据,未提交或回滚数据无法查出。

不可重复读问题:

a)事务一读取id=111111的角色信息。可以看出角色名是董事长。

b)事务二更新id=111111的角色名为董事长(代理)并提交事务。可以看出角色已更改为董事长(代理)

c)事务一再次读取id=111111的角色信息。可以看出获取的角色名是董事长(代理),是不是给人一种恍惚的感觉,这就是读已提交的魅力。

        结论:读已提交隔离级别中,在同一个事务中,对同一条数据多次读取,可能会出现不同的结果,原因是其他事务对该条数据进行更新并提交了事务。这就是常说了不可重复读问题,一直读取的是已提交的数据。

幻读问题:

a)事务一读取角色全表数据。仔细查看具体的名称信息哦

b)事务二更改id=111111的角色名为董事长,并提交事务。可以看出数据已更新。

c)事务一再次读取角色全表数据。可以看出id=111111的角色名与第一次有些不同了。

     结论:看到幻读现象是不是与不可重复读有异曲同工之妙,其实不然,是因为在读已提交级别中看出来是差不多的(因为读取的都是已提交数据),但是他们的作用范围是不一样的,不可重复读是针对同一条数据,幻读是针对同一批数据。如果还有些疑问可以在 可重复读 与 串行化 中找到答案。

      总结:读已提交隔离级别中,事务只能读取已提交的数据,对于未提交或回滚数据是无法读取的,它解决了脏读,对于不可重复读与幻读还未解决。

3.3、可重复读

3.3.1、设置隔离级别

# 设置会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
# 设置全局隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
# 查询事务隔离基本
SHOW VARIABLES LIKE '%transaction_isolation%';

3.3.2、验证

注意:脏读就不再可重复读级别中展现了(读已提交已解决),大家要回想哈读已提交哦。

解决不可重复读问题:

a)事务一读取id=222222角色信息。

b)事务二更新id=222222信息,并提交事务。图中可看出数据以更新。

。 

c)事务一在读取id=222222角色信息。

        怎么回事,为什么读取的不是事务二已提交的数据,???,难道是我们Mysql服务出现问题了吗?其实不是的,这就是可重复读隔离级别的作用,在我们事务开启第一次读取就已经明确数据,不管其他事务对该条数据如何更改,事务一也只能读取第一次获取到的数据。是不是与读已提交有点不一样了,大家是不是对读已提交时产生的疑问有了答案,那下面我们继续看幻读。

幻读问题:

a)事务一读取角色全表信息。

b)事务二新增实习角色并提交事务。图中可看出数据新增成功。

c)事务一更新第一次查询未查出角色,id=bbbbbb的角色名信息,并再次角色全表信息。可以看出数据与第一次不一样了,这就是幻读现象。

        结论:可重复读隔离级别中,在同一个事务中,对同一条数据多次读取,查询的结果数据是一样的。

        总结:可重复读隔离级别中,同一个事务中对同一条SQL查询多次查询结果都是一样的,他解决了脏读,不可重读的问题,幻读未解决。但是只要在查询中不更改不在第一次快照表的数据,其实幻读很难出现。

3.4、串行化

3.4.1、设置隔离级别

# 设置会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
# 设置全局隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
# 查询事务隔离基本
SHOW VARIABLES LIKE '%transaction_isolation%';

3.4.2、验证

        注意:串行化隔离级别主要解决幻读问题,但是这个隔离级别对高并发场景下性能有所降低。

a)事务一查询角色全表数据。

b)事务二新增《测试》角色信息,并提交事务。

      可以看出,事务二无法插入数据,原因就是事务一还未提交,需要等待事务一提交后,事务二才会执行。 

        从上可以看出,串行化隔离级别中事务与事务之间是根据串行链路执行的,只有等前面事务完成后,后面的事务才可执行。所以 串行化隔离级别中根本就不存在上诉的三种问题。相应的,他的性能也很低,并发越高,性能越低。

3.5、总结

        通过上述的隔离级别讲解,大家都有一定的认识,也有了一定的了解。可能大家都有一个疑问,不可重复读与幻读之间总感觉有点相识,但是又有点不同,其实之所以会出现这种问题,其实本质性他们都是读取了已提交的数据后产生的后续现象,不同的展现形式,可重复读级别中的快照缓存其实本质上也为我们规避了幻读的情况,大家也不用过多的担心。可重复读隔离级别中基本上在业务环境中不会出现幻读,原因是我们是基于读取的数据进行更改,不会对未出现的数据进行更改,也不会出现幻读问题,如果不放心,其实可以使用锁来保证,但是不建议这么使用。可重复读基本上就已经满足我们业务需求了,幻读只是很少场景才会出现并不会频繁的出现,不必担心。

4、事务原理

        说事务原理之前我们还是先回顾哈事务四大特性(ACID),原理也是基于特性来讲解的。

原子性,一致性,隔离性,持久性四个特性可以分成两大模块来分析,一种是基于Log文件,一种是基于锁+MVVC的。Log文件有(原子性、一致性、持久性),锁+MVVC只有隔离性。那下面我们就分别展开讲讲。

4.1、LOG文件

4.1.1、Redo Log 文件

        Redo Log文件就是事务提交后将数据存储物理数据(可以看作是真实数据),它的作用就是保证脏页刷新失败后(系统崩溃等),进行数据恢复。Redo Log文件保证了四大特性的持久性,即事务一旦提交或回滚,对数据库的操作永久性的不可更改的。

        Redo Log 分为 Redo Log Buffer 与 Redo Log File,一个是在内存中,一个在磁盘中,为啥会分成两个部分,旨在保证性能,减少IO。我们举例说明,如果没有Redo Log Buffer,那是不是事务每次提交过程中的Log数据都需要写入Redo Log File磁盘文件中,这样一想没啥问题,但是忽略了频繁IO的操作,我们都知道IO是很浪费性能的,虽然Redo Log File是添加在尾部的,比随机IO强,但是次数多了,其实也没啥区别了。除了这个问题外,还有一个同步失败的问题,一旦我们成功的告诉用户数据成功了,但是系统突然崩溃重启,那我们是不是就丢失数据了。基于上面的两种情况,官方就加入了缓存,其次减少IO,再次保证恢复。

4.1.2、Undo Log文件

        Undo Log 回滚日志,主要记录事务执行过程中数据变更前的数据(逻辑数据),如果对同一条数据多次更新,它会生成一条操作记录链(即:Roll Pointer指针)。它有两个作用:事务回滚,MVVC多版本并发控制(后续文章讲解)。逻辑数据就是用户操作数据相反的命令,例如 insert 命令,undo Log会记录 delete 命令,update 命令,会记录相反的 update命令,一旦事务回滚,就是执行本次事务中记录的相反命令来保证原子性与一致性。 事务提交则Undo Log日志并不会立马删除,原因是MVVC多版本控制中会使用,也就是上面可重复读为啥每次都获取相同数据的原理了。

        Undo Log日志保证了原子性与一致性。

        Undo Log日志存储在Segment(段中),就是之前我们说的回滚段,一个表空间中最多允许128个段,一个段中有一个回滚段,一个回滚段有1024个回滚日志插槽(undo log segment solt)。每次事务开启时会获取一个回滚段slot,用于事务提交与回滚。为啥会有1024个插槽,主要为了提升并发能力。相当于最多支持 1268*1024=131072个并发。

        undo log日志文件会在Page Cleaner Thread内部线程清理不需要的日志记录。

4.2、锁+MVVC

        锁 麻烦耐心等待哈,后续会出新文档。

        MVVC 会在下一版本中。

        敬请期待!!!

标签:存储,隔离,级别,事务,InnoDB,提交,Mysql,数据,读取
From: https://blog.csdn.net/2401_85207246/article/details/144571056

相关文章

  • 医院食堂订餐系统Python+Vue3+Django(Pycharm毕业设计 mysql)
    文章目录具体实现截图项目介绍和开发技术介绍开发技术核心代码部分展示项目结构分析文章目录/写作提纲参考源码/演示视频获取方式具体实现截图项目介绍和开发技术介绍创新之处(1)系统资源闭环整合,实现了综合功能高度集成。(2)采用DJANGO框架,开发软件更加方便、快......
  • C语言——整型数据在内存中的存储
    整型数组在内存中的存储一、大小端存储1.大端存储(大端字节序存储)2.小端存储(小端字节序存储)>给大家一个题目,设计一个程序判断当前机器的字节序.二、原码、反码和补码1.*补充2.例题1.2.3.4.5.6.一、大小端存储1.大端存储(大端字节序存储)将一个数据的低位字节内容......
  • 【Nginx应用】Windows下使用Nginx反向代理访问MySQL数据库
    环境说明1和2互通,2和3互通,1和3不通,想要在1上访问3上的msyql服务。实现步骤如下:一、安装nginx1.1下载nginx下载地址https://nginx.org/download/nginx-1.26.2.zip1.2将下载的安装包上传到192.168.221.134运维跳板机,并解压1.3nginx常用操作1.3.1启动nginx#进入......
  • mysql把行转成列
    原始数据:codenameREPORT_NAMEamount1A2023销量1001A2022销量2001A2021销量4001B2023销量3001B2020销量100输出数据:codename2023销量2022销量2021销量2020销量1A10020040001B30000100SQL:SELECTc......
  • mysql按某字段值排序并取前n行
    原始数据:codenameyearamount1a20191001a20202001a20211901a20221802b20181902b20192002b2020230输出数据:codenameyearamount1a20211901a20221802b20192002b2020230SQL:selectcode......
  • mysql把某字段多行值拼接成一行
    原始数据:codenamez_date1aaa202412201aaa202412211aaa202412222bbb202412192bbb20241220输出结果:codenamez_date1aaa20241220,20241221,202412222bbb20241219,20241220SQL:selectcode,name,count(n),GROUP_CONCAT(......
  • MySQl数据库数据的时间比当前时间少了8小时处理
    在mysql中如何设置时间在MySQL中设置时间主要涉及到两个方面:一是设置数据库服务器的系统时间,二是设置表中的时间字段。一、设置数据库服务器的系统时间MySQL数据库服务器的系统时间通常与操作系统的时间同步。如果你需要调整MySQL服务器的时间,可以通过以下命令:代码语言:txt复......
  • 【云服务器教程】3分钟搞定MySQL远程访问配置
    本文将介绍如何在云服务器上快速配置MySQL远程访问权限,包含必要的安全设置。一、配置云服务器(以阿里云为例)登录阿里云控制台配置安全组:开放3306端口配置防火墙:#开放3306端口sudofirewall-cmd--permanent--add-port=3306/tcpsudofirewall-cmd--reload二、配置My......
  • Mysql5.7配置主从实际操作记录
    ......
  • 用pandas导入含嵌套字典的json文件至mysql数据库
    需要导入的文件格式如下,要把data-diff数组里的所有元素导进去,对于某些json文件还需要添加日期字段。{"rc":0, "rt":6, "data":{ "total":197, "diff":[ { "f1":1, "f2":295.5, "f3":{"f4":......