当前位置: 首页 > 科技观察

旁边的高T问了Java面试官这样一个问题...

时间:2023-03-20 02:00:01 科技观察

大家好,我是JDL京东物流技术开发部邢焕杰,今天分享一道京东面试真题。听面试候选人时坐在我桌边的高T(high,真high)问的一个问题。他问,能谈谈MySQL的事情吗?MVCC懂吗?话不多说,本文将深入分析MySQL事务和MVCC的实现原理。交易定义及四大特点什么是交易?它是用户定义的一系列数据库操作。这些操作可以看作是一个完整的逻辑处理工作单元,要么全部执行,要么根本不执行,是不可分割的工作单元。事务(简称ACID)的四大特性:原子性(Atomicity):事务是一个不可分割的工作单元,事务中包含的操作要么执行,要么不执行。一致性:事务必须将数据库从一种一致状态更改为另一种状态。一致性和原子性是密切相关的。隔离性:一个事务的执行不能被其他事务干扰。即一个事务内使用的操作和数据与其他并发事务隔离,并发执行的事务之间不能相互干扰。持久性(Durability):一旦一个事务被提交,它对数据库中数据的改变是永久性的。应该是永久性的,后续的其他操作或故障应该不会对其产生任何影响。事务中常见的问题脏读:即使一个事务A没有提交,它的数据修改也可以被其他事务B看到,B读取了A事务未提交的数据。这个数据可能是错误的。有可能A不想提交此数据。这只是A事务修改数据过程中的一个中间数据,却被B事务读取了。这种行为称为脏读,这种数据称为脏数据不能重复。读(不可重复读):在事务A中多次读取同一个数据,但是在读取过程中,事务B修改了数据,导致数据发生变化,事务A再次读取,此时数据不同于第一次读,称为不可重复幻读(phantomread):一个事务多次查询数据库,结果查询到的数据项个数不一样,而一个事务在多次查询过程中区间内,事务B写入了一些满足查询条件的数据(这里的写入可以是update、insert、delete)。如果事务A再次检查,就像幻觉一样。怎么突然变了?这么多,这种现象叫做幻读隔离级别——问题产生的原因是多个事务相互影响,没有很好地隔离,也就是我们刚才说的事务的四个特性中的隔离(Isolation)出现尚未设置相关事务的隔离级别。让我们看看事务具有什么样的隔离级别。Transactionseesreadcommitted(读提交RC):一个事务提交后,它所做的改变会被其他事务看到。可重复读(repeatablereadRR):事务执行过程中看到的数据总是和事务开始时看到的数据一致。当然,在可重复读隔离级别下,未提交的修改对于其他事务也是不可见的。Serializable:顾名思义,对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当发生读写锁冲突时,后面访问的事务必须等待前面的事务完成后才能继续执行。下面通过一个例子来更直观地理解这四种隔离级别与上面脏读、不可重复读、幻读问题之间的关系。让我们讨论一下当事务处于不同的隔离级别时,V1、V2和V3是什么。Differentvaluesreaduncommitted(RU):A事务可以读取B事务修改的值,即使B事务没有提交。所以V1为200V1:200V2:200V3:200ReadCommit(RC):事务B未提交时,事务A看不到事务B修改的值,只有提交后才能看到V1:100V2:200V3:200Repeatableread(RR):一个事务多次读取数据,总数据与第一次读取相同,V1:100V2:100V3:200Serialization(S):事务A正在执行,事务B将被锁定,事务B在事务A执行完后可以继续执行。V1:100V2:100V3:200MVCC原理MVCC(Multi-VersionConcurrencyControl)多版本并发控制是数据库控制并发访问的一种手段。特别需要注意的是,MVCC只在读提交(RC)和可重复性(RR)这两个事务隔离级别下有效。它在数据库引擎(InnoDB)级别实现,用于处理读写冲突(不加锁)。,MVCC是如何实现来提高访问性能的?依赖于版本链和一致性视图1.版本链版本链是一个链表,将每条数据的修改记录链接起来。那么这个版本链是如何形成的,每条数据又是如何链接在一起的呢?事实上,情况就是这样。对于InnoDB存储引擎的表,它的聚簇索引记录包含两个隐藏字段trx_id:存储修改这条数据的事务id,只有当事务操作某些表的数据时发生改变操作时(update,delete,insert),会分配一个唯一的事务id,这个事务id是一个递增的roll_pointer:指针,指向最后修改的记录row_id(非必填):当有主键或不允许为null时,该字段不可使用唯一键时包括在内。如果当前数据库有这样的数据,假设这个数据是由一个事务ID为100的事务插入的,那么这个数据的结构如下:后来,事务200,事务300,分别要修改这个数据:所以此时的版本链如下:我们每次更改数据都会插入一个undolog,记录的roll_pointer指针会指向上一条记录,如图:第一条数据是小杰,事务ID为100,交易ID为200,姓名由小杰改为A,交易ID为200,姓名由A改为B,交易ID为300,姓名由B改为C,所以链表形成是C->B->A->小杰(从最新的数据到最旧的数据)2.一致性视图(ReadView)需要判断版本链中的哪个版本对当前事务可见,所以就有了一致的性观观念。其中,四个属性比较重要m_ids:生成ReadView时,当前活跃的读写事务的事务id列表min_trx_id:m_ids的最小值max_trx_id:m_ids+1的最大值creator_trx_id:生成该事务的事务idtransaction,简单开启交易没有交易id,默认为0,creator_trx_id为0。版本链中的当前版本是否可以被当前交易看到,应该根据以下几种情况,根据这四个属性来判断。当trx_id=creator_trx_id:当前交易可以看到自己修改的数据。可以看出,当trx_id=max_trx_id:时,说明产生这条数据的事务是在ReadView产生之后开始的。它是不可见的。当min_trx_id<=trx_id