热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MySqlACID实现原理

MySqlACID实现原理1.MVCC-多版本并发控制

MySql ACID实现原理

1. MVCC-多版本并发控制

1.0 什么是MVCC

为了保证一致性,可以使用锁,但是锁会降低读写效率,MVCC就是为了保证读写效率的一个替代方案。

MVCC是基于快照读和可见性算法的一个多版本控制算法,即在不同的隔离级别下采用不同的可见性算法,解决读写冲突的算法。

1.1 事务隔离级别

隔离级别
读未提交
RC-读已提交可以读取到最新的结果记录;每次进行快照读的时候都会生成新的readview
RR-可重复读(默认)不可以读取到最新的结果记录;只有第一次执行快照读的时候才会生成readview
可序列化

1.2 快照读、当前读和Read View

快照读读取的是历史版本的记录select …
当前读读取的是数据的最新版本,总是读取到最新的数据select … lock in share mode
select … for update
update
delete
insert

数据隐藏字段:

  • DB_TRX_ID:最近创建或者修改该记录的事务id
  • DB_ROW_ID:隐藏主键
  • DB_ROLL_PTR:回滚指针,指向上一个版本

undolog:回滚日志。保存了数据的历史版本状态,数据的回滚指针指向在undolog中的地址。undolog是逻辑日志,记录的是一条使日志状态回滚的记录;

redolog:重做日志,是物理的日志。

readview:事务在进行快照读的时候产生的读视图,不同隔离级别下readview生成的时机是不同的;

  • trx_list:系统活跃的事务id
  • up_limit:列表中最小的事务id
  • low_limit_id:系统尚未分配的下一个事务id
  • creator_trx_id: 创建当前read view的事务版本号;

1.3 可见性算法

可见性算法基于readView

if db_trx_id

  • 如果数据事务id小于当前readview的最小活跃事务id,说明该数据一定是该当前readView生成之前就修改了的;
  • 如果数据事务id等于readView的事务版本号,说明这个数据就是当前事务生成的;

else if db_trx_id >= low_limit_id:不显示

  • 如果数据事务id大于readView的最大id时,说明该数据是在该readView生成之后产生的

else db_trx_id是否在活跃事务(trx_ids)中

  • 不存在:说明readView产生时事务已经commit了,因此可以显示
  • 已存在:说明readView生成时,该事务还活跃,并且没有commit,因为不可见

2. 四大特点-ACID

特性概念实现方式
原子性要么全部成功,要么全部失败undolog
隔离性MVCC、undolog
持久性redolog->write ahead log
一致性

2.1 持久性

持久性的实现:由于磁盘查询比较慢,mysql使用了缓存(Buffer Pool)。但是如果mysql宕机,缓存中尚未存入磁盘的数据就回丢失。而数据修改时,除了修改缓存中的数据,还会用redo log记录这次操作,如果服务器宕机重启时就可以使用redolog对数据库进行恢复。redolog采用的是WAL,从而满足了持久性的要求。在事务提交时,也需要将redolog的日志存入磁盘。

write ahead log:先写日志,再写数据。因为将数据写入磁盘是随机读写,而写日志是顺序读写,顺序读写速度快于随机读写;

redolog和binlog:

  • 作用不同:redo log是用于crash recovery的,保证MySQL宕机也不会影响持久性;binlog是用于point-in-time recovery的,保证服务器可以基于时间点恢复数据,此外binlog还用于主从复制。
  • 层次不同:redo log是InnoDB存储引擎实现的,而binlog是MySQL的服务器层(可以参考文章前面对MySQL逻辑架构的介绍)实现的,同时支持InnoDB和其他存储引擎。
  • 内容不同:redo log是物理日志,内容基于磁盘的Page;binlog的内容是二进制的,根据binlog_format参数的不同,可能基于sql语句、基于数据本身或者二者的混合。
  • 写入时机不同:binlog在事务提交时写入;redo log的写入时机相对多元:

为什么redolog的存盘比直接将缓存中的数据写入磁盘更快:

  1. 刷脏是随机IO,但是redolog是追加操作,是顺序io
  2. 刷脏以page为单位,每个页的小修改都要整页写入;而redolog只包含真正需要写入的部分,无效io大量减少;

2.2 原子性

原子性的实现:使用undolog实现原子性。当事务对数据库进行修改时,innodb会生成相应的undolog,如果此时事务执行失败或者调用了rollback,导致事务出现回滚,就可以利用undolog进行数据恢复。

2.3 隔离性

隔离性的实现:隔离性由锁与MVCC共同实现。其中锁解决写写冲突,MVCC解决读写冲突

读写冲突:读写冲突问题有脏读、不可重复读、幻读;innodb使用mvcc可以在不同隔离级别下解决这些问题的出现;

写写冲突:隔离性要求同一条数据在同一时间只能被一个事务进行修改,因此使用锁来控制;

3. MVCC解决读写冲突

3.1 脏读、不可重复读、幻读

脏读:读取到了其他事务未提交的数据修改;

不可重复度:一个事务中几次读取的数据不一致;这是由于事务执行期间,有其他事务修改了数据并且提交;

幻读:一个事务中几次读取的数据条数不一致,也可以说是读取到了其他事务对数据的增删操作;这是由于事务执行期间,有其他事务增加或删除了数据并提交;

对应隔离级别:

隔离级别脏读不可重复读幻读
RU-读取未提交
RC-读取已提交×
RR-可重复读××
读取序列化×××

MVCC在不同隔离级别下的可见性算法不同,因此在不同级别下可以防止脏读、不可重复读、幻读等问题的出现;

在RC级别下,每一个快照读都会生成并获取最新的readView;

在RR级别下,只有事务的第一个快照读才会创建readView;

3.2 脏读

在这里插入图片描述

当事务A在T3时间节点读取zhangsan的余额时,会发现数据已被其他事务修改,且状态为未提交。此时事务A读取最新数据后,根据数据的undo log执行回滚操作,得到事务B修改前的数据,从而避免了脏读

3.3 不可重复读

在这里插入图片描述

当事务A在T2节点第一次读取数据时,会记录该数据的版本号(数据的版本号是以row为单位记录的),假设版本号为1;当事务B提交时,该行记录的版本号增加,假设版本号为2;当事务A在T5再一次读取数据时,发现数据的版本号(2)大于第一次读取时记录的版本号(1),因此会根据undo log执行回滚操作,得到版本号为1时的数据,从而实现了可重复读。

3.4 幻读

  • innodb在RR隔离等级下,使用next-key lock避免了幻读现象;
  • next-key lock:是一种组合锁,间隙锁和行锁合称next-key lock;next-key lock是前开后闭的;

在这里插入图片描述

当事务A在T2节点第一次读取0

4. 锁

单条索引记录上加锁,record lock锁住的永远是索引,而非记录本身,即使该表上没有任何索引,那么innodb会在后台创建一个隐藏的聚集主键索引,那么锁住的就是这个隐藏的聚集主键索引。所以说当一条sql没有走任何索引时,那么将会在每一条聚集索引后面加X锁,这个类似于表锁,但原理上和表锁应该是完全不同的。

4.1 锁的分类

按粒度分:分为表锁和行锁(Record Lock),不同引擎支持的粒度不一样,myisam只支持表锁,innodb支持表锁和行锁;当没有索引时,行锁会失效,变成表锁;等值判断时,varchar必须添加单引号,否则mysql会做自动类型转换,并且导致索引失效;

按操作分:分为写锁和读锁。读锁是共享锁,其他事务可以读取但是不可以写;写锁是排他锁,其他事务不可以进行读取或写操作;

4.2 悲观锁和乐观锁

悲观锁:悲观锁就是数据库层面的锁,如读写锁;但是读写锁会降低数据库读写的效率;

乐观锁:乐观锁是一种基于数据版本实现的并发控制,是不使用锁的。在读写事务,在真正的提交之前,不加读/写锁,而是先看一下数据的版本/时间戳,等到真正提交的时候再看一下版本/时间戳,如果两次相同,说明别人期间没有对数据进行过修改,那么就可以放心提交;如果遇到冲突,则需要回退。

悲观锁和乐观锁使用:在资源冲突不激烈的场合,使用乐观锁性能较好;但是如果资源冲突严重,乐观锁的实现会导致事务反复回滚重试,这样不如直接使用悲观锁。

4.3 乐观锁和MVCC

MVCC:MVCC是用于解决读-写冲突的无锁并发控制,基于快照隔离机制进行多版本并发控制,即为每一个修改都保存一个版本快照;主要解决了脏读和不可重复读;

乐观锁:乐观锁是用于解决写-写冲突的无锁并发控制,主要通过版本比较和回退避免了写-写冲突的问题;

4.4 间隙锁(Gap Lock)

在RR隔离级别下无法避免幻读的问题,因此引入间隙锁来解决幻读问题。

行锁和MVCC都是针对已有的数据进行的控制,但是对新增的数据没法进行控制,因此需要对一定范围内的数据进行加锁;在RR隔离级别下,数据库是通过行锁和间隙锁共同组成的;

在进行范围判断时,会将范围类的所有键值都锁定,即使该键值并不存在;

使用间隙锁的条件:必须是在RR级别下。是一个范围的当前读操作或者是一个非唯一索引的等值判断;

4.5 Next Key Lock

Next Key Lock是一种组合锁,间隙锁和行锁合称next-key lock;next-key lock是前开后闭的;

mysql加锁的基本单位是next-key lock;

4.6 加锁规则

加锁规则包含两个原则,两个优化,一个bug:

  1. 原则1:加锁单位是next-key lock,next-key lock是前开后闭的;
  2. 原则2:查找过程中访问到的对象才会加锁;
  3. 优化1:索引上的等值查询,向唯一索引加锁时,next-key lock退化为行锁
  4. 优化2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock退化为间隙锁
  5. bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止;

推荐阅读
  • MySQL中的MVVC多版本并发控制机制的应用及实现
    本文介绍了MySQL中MVCC的应用及实现机制。MVCC是一种提高并发性能的技术,通过对事务内读取的内存进行处理,避免写操作堵塞读操作的并发问题。与其他数据库系统的MVCC实现机制不尽相同,MySQL的MVCC是在undolog中实现的。通过undolog可以找回数据的历史版本,提供给用户读取或在回滚时覆盖数据页上的数据。MySQL的大多数事务型存储引擎都实现了MVCC,但各自的实现机制有所不同。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • 本文详细介绍了MysqlDump和mysqldump进行全库备份的相关知识,包括备份命令的使用方法、my.cnf配置文件的设置、binlog日志的位置指定、增量恢复的方式以及适用于innodb引擎和myisam引擎的备份方法。对于需要进行数据库备份的用户来说,本文提供了一些有价值的参考内容。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 从Oracle安全移植到国产达梦数据库的DBA实践与攻略
    随着我国对信息安全和自主可控技术的重视,国产数据库在党政机关、军队和大型央企等行业中得到了快速应用。本文介绍了如何降低从Oracle到国产达梦数据库的技术门槛,保障用户现有业务系统投资。具体包括分析待移植系统、确定移植对象、数据迁移、PL/SQL移植、校验移植结果以及应用系统的测试和优化等步骤。同时提供了移植攻略,包括待移植系统分析和准备移植环境的方法。通过本文的实践与攻略,DBA可以更好地完成Oracle安全移植到国产达梦数据库的工作。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 本文介绍了一个React Native新手在尝试将数据发布到服务器时遇到的问题,以及他的React Native代码和服务器端代码。他使用fetch方法将数据发送到服务器,但无法在服务器端读取/获取发布的数据。 ... [详细]
  • 背景应用安全领域,各类攻击长久以来都危害着互联网上的应用,在web应用安全风险中,各类注入、跨站等攻击仍然占据着较前的位置。WAF(Web应用防火墙)正是为防御和阻断这类攻击而存在 ... [详细]
author-avatar
细妹很快乐
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有