mysql的mvcc实现原理详解_MYSQLMVCC实现原理详解MVCC(Multi Version Concurrency Control的简称),代表多版本并发控制。与MVCC相对的,是基于锁的并发控制,Lock-Based Concurrency Control)。
MVCC最⼤的优势:读不加锁,读写不冲突。在读多写少的OLTP应⽤中,读写不冲突是⾮常重要的,极⼤的增加了系统的并发性能
了解MVCC前,我们先学习下Mysql架构和数据库事务隔离级别
MYSQL 架构
MySQL从概念上可以分为四层,顶层是接⼊层,不同语⾔的客户端通过mysql的协议与mysql服务器进⾏连接通信,接⼊层进⾏权限验证、连接池管理、线程管理等。下⾯是mysql服务层,包括sql解析器、sql优化器、数据缓冲、缓存等。再下⾯是mysql中的存储引擎
层,mysql中存储引擎是基于表的。最后是系统⽂件层,保存数据、索引、⽇志等。
事务隔离级别
⼤家都知道数据库事务具备ACID特性,即Atomicity(原⼦性) Consistency(⼀致性), Isolation(隔离性), Durability(持久性)
原⼦性:要执⾏的事务是⼀个独⽴的操作单元,要么全部执⾏,要么全部不执⾏
webservice现在用的多吗⼀致性:事务的⼀致性是指事务的执⾏不能破坏数据库的⼀致性,⼀致性也称为完整性。⼀个事务在执⾏后,数据库必须从⼀个⼀致性状态转变为另⼀个⼀致性状态。
隔离性:多个事务并发执⾏时,⼀个事务的执⾏不应影响其他事务的执⾏,SQL92规范中对隔离性定义了不同的隔离级别:
读未提交(READ UNCOMMITED)->读已提交(READ COMMITTED)->可重复读(REPEATABLE READ)->序列化(SERIALIZABLE)。隔离级别依次增强,但是导致的问题是并发能⼒的减弱。
隔离级别脏读不可重复读幻读概念
READ UNCOMMITED
√
√
√
事务能够看到其他事务没有提交的修改,当另⼀个事务⼜回滚了修改后的情况,⼜被称为脏读dirty read
READ COMMITTED
×
√
√
事务能够看到其他事务提交后的修改,这时会出现⼀个事务内两次读取数据可能因为其他事务提交的修改导致不⼀致的情况,称为不可重复读
REPEATABLE READ
×
×
√
事务在两次读取时读取到的数据的状态是⼀致的
SERIALIZABLE
×
×
×
可重复读中可能出现第⼆次读读到第⼀次没有读到的数据,也就是被其他事务插⼊的数据,这种情况称为幻读phantom read, 该级别中不能出现幻读
⼤多数数据库系统的默认隔离级别都是READ COMMITTED(但MySQL不是),InnoDB存储引擎默认隔离级别REPEATABLE READ,通过多版本并发控制(MVCC,Multiversion Concurrency Control)解决了幻读的问题。
MYSQL 事务⽇志
事务⽇志可以帮助提⾼事务的效率。使⽤事务⽇志,存储引擎在修改表的数据时只需要修改其内存拷
贝,再把该修改⾏为记录到持久在硬盘上的事务⽇志中,⽽不⽤每次都将修改的数据本⾝持久到磁盘。事务⽇志采⽤的是追加的⽅式,因此写⽇志的操作是磁盘上⼀⼩块区域内的顺序I/O,⽽不像随机I/O需要在磁盘的多个地⽅移动磁头,所以采⽤事务⽇志的⽅式相对来说要快得多。事务⽇志持久以后,内存中被修改的数据在后台可以慢慢地刷回到磁盘。⽬前⼤多数存储引擎都是这样实现的,我们通常称之为预写式⽇志(Write-Ahead Logging),修改数据需要写两次磁盘。
如果数据的修改已经记录到事务⽇志并持久化,但数据本⾝还没有写回磁盘,此时系统崩溃,存储引擎在重启时能够⾃动恢复这部分修改的数据。
MySQL Innodb中跟数据持久性、⼀致性有关的⽇志,有以下⼏种:
Bin Log:是mysql服务层产⽣的⽇志,常⽤来进⾏数据恢复、数据库复制,常见的mysql主从架构,就是采⽤slave同步master的binlog实现的
Redo Log:记录了数据操作在物理层⾯的修改,mysql中使⽤了⼤量缓存,修改操作时会直接修改内存,⽽不是⽴刻修改磁盘,事务进⾏中时会不断的产⽣redo log,在事务提交时进⾏⼀次flush操作,保存到磁盘中。当数据库或主机失效重启时,会根据redo log进⾏数据的恢复,如果redo log中有事务提交,则进⾏事务提交修改数据。
mysql面试题详解
Undo Log: 除了记录redo log外,当进⾏数据修改时还会记录undo log,undo log⽤于数据的撤回操作,它记录了修改的反向操作,⽐如,插⼊对应删除,修改对应修改为原来的数据,通过undo log可以实现事务回滚,并且可以根据undo log回溯到某个特定的版本的数据,实现MVCC
MVCC实现
MVCC是通过在每⾏记录后⾯保存两个隐藏的列来实现的。这两个列,⼀个保存了⾏的创建时间,⼀个保存⾏的过期时间(或删除时间)。当然存储的并不是实际的时间值,⽽是系统版本号(system version number)。每开始⼀个新的事务,系统版本号都会⾃动递增。事务开始时刻的系统版本号会作为事务的版本号,⽤来和查询到的每⾏记录的版本号进⾏⽐较。
fortune是什么车下⾯看⼀下在REPEATABLE READ隔离级别下,MVCC具体是如何操作的。
SELECT
InnoDB会根据以下两个条件检查每⾏记录:
InnoDB只查版本早于当前事务版本的数据⾏(也就是,⾏的系统版本号⼩于或等于事务的系统版本号),这样可以确保事务读取的⾏,要么是在事务开始前已经存在的,要么是事务⾃⾝插⼊或者修改过的。
⾏的删除版本要么未定义,要么⼤于当前事务版本号。这可以确保事务读取到的⾏,在事务开始之前未被删除。
只有符合上述两个条件的记录,才能返回作为查询结果
INSERT
InnoDB为新插⼊的每⼀⾏保存当前系统版本号作为⾏版本号。
DELETE
InnoDB为删除的每⼀⾏保存当前系统版本号作为⾏删除标识。
UPDATEmatlab怎么编程递归算法
InnoDB为插⼊⼀⾏新记录,保存当前系统版本号作为⾏版本号,同时保存当前系统版本号到原来的⾏作为⾏删除标识。
保存这两个额外系统版本号,使⼤多数读操作都可以不⽤加锁。这样设计使得读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的⾏,不⾜之处是每⾏记录都需要额外的存储空间,需要做更多的⾏检查⼯作,以及⼀些额外的维护⼯作
举例说明
transaction 1:
假设系统初始事务ID为1;
IDNAME创建时间过期时间
1
mi
1
undefined
2
kong
1
undefined
transaction 2:
SELECT
假设当执⾏事务2的过程中,准备执⾏语句(2)时,开始执⾏事务3:
transaction 3:
IDNAME创建时间过期时间
1
mi
1
undefined
2
盘点经典java游戏
kong
1
undefined
3
qu
3
undefined
事务3执⾏完毕,开始执⾏事务2 语句2,由于事务2只能查询创建时间⼩于等于2的,所以事务3新增的记录在事务2中是查不出来的,这就通过乐观锁的⽅式避免了幻读的产⽣
UPDATE
假设当执⾏事务2的过程中,准备执⾏语句(2)时,开始执⾏事务4:
transaction session 4:
InnoDB执⾏UPDATE,实际上是新插⼊了⼀⾏记录,并保存其创建时间为当前事务的ID,同时保存当前事务ID到要UPDATE的⾏的删除时间
IDNAME创建时间过期时间
1
mi
1
undefined
2
kong
1
float转成int4
2
fan
4
undefined
事务4执⾏完毕,开始执⾏事务2 语句2,由于事务2只能查询创建时间⼩于等于2的,所以事务修改的记录在事务2中是查不出来的,这样就保证了事务在两次读取时读取到的数据的状态是⼀致的
DELETE
假设当执⾏事务2的过程中,准备执⾏语句(2)时,开始执⾏事务5:
transaction session 5:
IDNAME创建时间过期时间
1
mi
1
undefined
2
kong
1
5
事务5执⾏完毕,开始执⾏事务2 语句2,由于事务2只能查询创建时间⼩于等于2、并且过期时间⼤于等于2,所以id=2的记录在事务2 语句2中,也是可以查出来的,这样就保证了事务在两次读取时读取到的数据的状态是⼀致的
参考:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论