MySQL事务实现原理系统架构设计师与体系机构
⽬录
socket面试题及答案是什么是事务
事务是数据库中⼀些列操作的集合,这个集合是按顺序逐个执⾏的。在mysql中,保证数据具备ACID特性,这种特性使得事务使⽤起来⾮常安全和⽅便。⽐如银⾏转账操作,使⽤事务就可以保证转账结果的正确,不同转账之间的隔离,转账过程中发⽣错误的回滚,以及机器崩溃的现场恢复。可以在99.99%的情况下保证我们数据安全。
事务具备ACID特性,分别是原⼦性、持久性、隔离性、⼀致性。
1、原⼦性指事务中的所有操作要么全部成功要么全部失败,不能成功⼀半。
2、持久性指事务执⾏中机器崩溃后,重启机器,能重新执⾏失败的事务,保证事务不会因为某种情况被抛弃。
3、隔离性是针对事务之间的并发提出的概念,mysql做出了不同的隔离级别,隔离级别越⾼,事务并发性能越低,⼀般默认采⽤可重复读级别。
4、⼀致性基于前三点特性所产⽣,即事务过程中⽆论发⽣什么,最终数据都是准确⽆误的。powershell教程循环
程序进程快捷键bin、redo、undo⽇志
每次update、insert、delete类型的SQL执⾏时都会先写三条⽇志。
bin log记录执⾏的每条SQL,⽤来做主从复制;
redo log记录修改内容和修改页的位置,⽤来维护持久性;
undo log记录相反类型的SQL,⽤来做rollback和实现mvcc。
事务数据读写直接操作的都是缓存,由操作系统定时刷新到磁盘。log以追加写的⽅式写⼊缓存,⼀般mysql默认设置log写⼊缓存⽴即刷新到磁盘,保证log数据不丢失。
隔离级别
脏读:事务A还未提交修改,事务B读取到的未提交数据是脏数据。(丢失更新:事务A修改记录完成,但还未提交;事务B也修改了该记录并提交,但是事务B由于其他原因回滚,导致事务A的修改失效。)mysql面试题acid>css 修改滚动条样式
不可重复读:事务A获得查询结果,在事务A提交前,事务B将某条数据修改并提交,事务A再次查询,两次查询结果不同。
幻读:和不可重复读相同的场景,但幻读专指数据的删除或插⼊,⽽不是修改。
读取已提交(解决1);可重复读(解决1、2);串⾏化(全部解决)。
MVCC实现原理
mvcc是乐观锁的⼀种实现⽅式,⽬的是解决读写互斥问题,增⼤并发程度。
场景举例:每次更新数据都为其记录⼀个递增的版本。线程A当第⼀次读取数据时,版本号为1;此时该数据被线程B修改,那么版本号变为2;线程A再次读取数据,发现版本号有变,此时可以根据不同的隔离级别来决定是否展⽰变更后的数据。
mysql中的mvcc通过隐藏列DB_TRX_ID、DB_ROLL_PTR和ReadView实现。DB_TRX_ID是该⾏记录当前的事务id,DB_ROLL_PTR指向该⾏在undo log中的位置,ReadView 是⼀个记录当前活跃事务id的链表。
当⼀⾏记录被修改时,undo⽂件中会存储它的相反操作,并且存有修改之前的版本号。每次修改会在undo⽂件中形成链式存储,链表头部是最近的版本,尾部是最⽼版本。
当事务在执⾏select操作之前,会先构造ReadView,并通过ReadView判断当前记录是否是可见的。ReadView中按序存储(事务id排序)着所有活跃事务id,如果当前记录的事务id⼩于ReadView中的最⼩值,意味着该记录已经被提交,则该记录可见。如果⼤于ReadView中最⼤值,那么该记录应当在之后的事务中提交,因此属于不可见。如果处于最⼤最⼩值之前,则需要通过⼆分查判断,事务id是否存在于ReadView中,如果存在,说明该记录的事务活跃,但⽆法判定事务是否已经提交,因此需要读取DB_ROLL_PTR,获取上⼀个版本的事务id,看看上个版本是否是可见的,通过层层递归,直到某⼀个之前的版本满⾜可见的要求。
可重复读实现原理
快照读。
场景1:在事务A两次查询中间,事务B修改数据的场景下,第⼀次查询的结果会作为快照保存,之后再次查询就都是快照内容。
这是由于快照读本质是mvcc实现的,因为事务A本⾝对数据操作,会导致事务A维护的版本号变更,再次查询,事务A查询的就是最新版本号数据。
mvcc在mysql中,通过隐藏字段DB_TRX_ID、DB_ROLL_PTR和undo log实现。DB_TRX_ID记录该
⾏记录⽬前的版本号,DB_ROLL_PTR记录该⾏之前版本在undo log中的位置。那么在上述场景1下,事务A通过DB_ROLL_PTR,可以直接获取被事务B修改之前的数据。
场景2:如果在事务B插⼊数据1之后,事务A也修改了数据1,那么事务A再次查询就会看到本不存在的数据1。可见不可重复读⽆法解决幻读。
若想解决幻读,需要使⽤mvcc+NextKey Locks(间隙锁+⾏锁)。
我们都知道InnoDB⽀持⾏锁,并且⾏锁是锁住索引。⽽间隙锁⽤来锁定索引记录间隙,确保索引记录的间隙不变。间隙锁是针对事务隔离级别为Repeatable Read或以上级别⽽已的,间隙锁和⾏锁⼀起组成了Next-Key Lock。当InnoDB扫描索引记录的时候,会⾸先对索引记录加上⾏锁,再对索引记录两边的间隙加上间隙锁(Gap Lock)。加上间隙锁之后,其他事务就不能在这个间隙插⼊记录。这样就有效的防⽌了幻读的发⽣。
默认情况下,InnoDB⼯作在Repeatable Read的隔离级别下,并且以Next-Key Lock的⽅式对索引⾏进⾏加锁。当查询的索引具有唯⼀性(主键、唯⼀索引)时,Innodb存储引擎会对Next-Key Lock进⾏优化,将其降为⾏锁,仅仅锁住索引本⾝,⽽不是范围(除⾮锁定不存在的值)。若是普通索引,则会使⽤Next-Key Lock将记录和间隙⼀起锁定。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论