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

面试官让我谈谈我对事务隔离机制的理解?我是这样回答的!

时间:2023-03-19 19:12:32 科技观察

1。简介和业务隔离是每个高级开发面试过程中必不可少的部分。我记得有一次采访某家公司。面试官现场问了这个问题。因为没有充分的准备,所以结果在意料之中。知道!今天我们就把事务隔离机制的原理一起过一遍,这样以后遇到这种问题的时候,我们就有所准备了!好了BB废话不多说,阿粉直接送你上车!说到交易,相信大家一定不陌生。我们在处理数据库时总是使用它。以转账为例,你想转100元给好友小张,此时银行卡余额至少要有100元。在转账过程中,程序会有查询余额、加减法、更新余额等一系列操作,必须保证这些操作是集成的。否则程序查完后,扣完余额前,你可以利用这个时间差,把你的100元再查一遍,然后再把钱转给另一个朋友。如果程序真的这样做了,银行就不会亏本了。奇怪的!在整个程序更新数据的过程中,这时候就会用到“事务”的概念。简单的说,事务就是保证一组数据库操作要么全部成功,要么全部失败!以MySQL为例,事务支持是在引擎层实现的。大家可能知道,MySQL是一个支持多引擎的系统,但并不是所有的引擎都支持事务。例如,MySQL的原生MyISAM引擎不支持事务。这也是MyISAM被InnoDB取代的重要原因之一。下面将以InnoDB为例,分析MySQL在事务支持方面的具体实现。希望通过这些案例,可以加深大家对MySQL事务原理的理解!,Consistency,Isolation,Durability)四个特性,即:原子性,一致性,隔离性和持久性。原子性和一致性很好理解,上面说了,要么全部成功,要么全部失败;持久化,也很容易理解,当数据发生变化时,可以将最新的结果记录到磁盘中永久保存;而隔离性则有点复杂。简单来说,就是将事务相互隔离。当多个事务同时处理一条数据时,它们不会相互影响。如果隔离性不够好,可能会出现脏读、不可重复读、幻读等情况。为此,隔离分为四个级别:从低到高分别是Readuncommitted、Readcommitted、Repeatableread、Serializable。这四个层次可以解决脏读、不可重复读、幻读等问题。.readuncommitted:俗称readuncommitted,意思是当一个事务还没有提交时,它所做的修改可以被其他事务看到。Readcommitted:俗称readcommit,意思是一个事务提交后,它所做的修改会被其他事务看到。可重复读:俗称可重复读,是指事务执行过程中看到的数据,与事务开始时看到的数据始终保持一致。同时,当其他事务未提交时,更改是不可见的。Serializable:俗称序列化,顾名思义,对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当发生读写锁冲突时,后面访问的事务必须等待前面的事务完成后才能继续执行。四种隔离级别中,“readcommit”和“repeatableread”比较难理解。下面就以一个例子来介绍一下这几个隔离级别的区别吧!假设数据表T只有一列,一行的值为1。mysql>createtableT(cint)engine=InnoDB;插入T(c)值(1);以下是按时间顺序执行两个事务的行为。我们来看看事务A在不同隔离级别下的不同返回结果,即图中V1、V2、V3的返回值分别是多少。如果隔离级别为“readuncommitted”,那么V1的值为2,此时事务B虽然还没有提交,但是结果已经被A看到了,所以V1、V2、V3都是2。如果隔离级别为“readcommitted”,则V1为1,事务B的更新只有提交后才能被A看到。所以V2和V3的值也是2。如果隔离级别是“可重复读”,V1和V2是1,V3是2。之所以V2还是1是为了遵循这个要求:数据当前事务在执行过程中看到的前后必须一致。如果隔离级别是“序列化”,那么在事务B执行“change1to2”时会被加锁。在事务A提交之前,事务B无法继续。所以从A的角度来看,V1和V2的值为1,V3的值为2。为什么会这样?一起分析一下吧!在实现上,当一个事务开始时,会在数据库中创建一个视图。访问时,以视图的逻辑结果为准。在“readcommitted”隔离级别下,这个视图是在每个SQL语句执行开始时创建的。在“可重复读”隔离级别下,这个视图是在事务开始的时候创建的,并且这个视图在事务存在的整个过程中都被使用。在“序列化”隔离级别下,直接使用锁来避免并行访问。在“readuncommitted”隔离级别下,直接返回记录上的最新值,没有视图概念。因此,在不同的隔离级别下,数据库的行为是不同的。比如Mysql数据库默认的隔离级别是“repeatableread”,而oracle和pgsql数据库默认的隔离级别是“readcommitted”。因此,对于一些从Oracle迁移到MySQL的应用,为了保证数据库隔离级别的一致性,一定要记得将MySQL隔离级别设置为“readcommitted”。配置方法是设置启动参数transaction-isolation的值为READ-COMMITTED。您可以使用showvariables查看当前的事务隔离级别。mysql>showvariableslike'%tx_isolation%';+--------------------+---------------+|变量名|值|+--------------------+----------------+|tx_isolation|REPEATABLE-READ|+--------------------+----------------+pass可以resetmysql>settx_isolation='READ-COMMITTED';综上所述,每个隔离级别都有自己的使用场景,需要根据自己的业务情况来决定使用!可能有同学会问,“读取并提交”就可以解决问题,为什么还需要“可重复读”的隔离机制呢?下面就以数据校对逻辑为例,介绍一下“可重复读”读的隔离好处!假设你正在管理一张个人银行账户表,一张表存储账户余额,另一张表存储账单明细。月末需要查看数据,即判断上月余额与当前余额的差额是否与本月账单明细一致。你一定希望在数据校对过程中,即使用户有新的交易,也不会影响你的校对结果。这时候使用“可重复读”隔离级别就显得极为实用和方便,因为事务启动时的视图可以认为是静态的,不会受到其他事务更新的影响。3、如何理解脏读、不可重复读、幻读?上面我们介绍了隔离机制。当多个事务同时处理一条数据时,会出现一些问题。具体来说:脏读、不可重复读和幻读。3.1.脏读脏读是指从其他事务中读取未提交的数据。Uncommitted表示这些数据可能会保存到数据库中,也可能会回滚而不保存到数据库中。当数据回滚时,就意味着数据不存在,这就是脏读!以上面的案例为例,当隔离级别为“读未提交”时,V1的值为2。如果事务B没有提交数据,就相当于读取了一条不存在的数据,会造成脏阅读。一旦发生脏读,会非常严重,对整个业务的影响也会很大。3.2.不可重复读不可重复读是指在一个事务内,开始时读取的数据与事务结束前任意时刻读取的同一批数据不一致。以上述案例为例,当隔离级别为“readcommitted”时,会产生同一个事务,多次读取同一条数据会产生不同的结果。3.3.幻读幻读和不可重复读有些相似。在同一个事务中多次读取同一条数据的结果是不一致的,只是表达的侧重点不同。比如事务A在查询某条记录是否存在,如果不存在则插入。准备插入的时候,事务B突然提交一条insert语句,提交速度比事务A快,此时事务A正在插入数据,突然报错,无法插入,出现幻读这次!不可重复读侧重于表达:read-read,幻读侧重于表达:read-write,writing用于验证读是鬼。上面提到的“脏读”、“不可重复读”、“幻读”问题,其实是由于并发操作导致从数据库读取数据不一致造成的。首先,阅读未提交。它的性能是最好的,也可以说是最残酷的方法,因为它根本不加锁,所以根本没有隔离效果,可以理解为没有隔离。再来说说连载。连载就相当于我上面说的。当一个人的请求被处理后,其他人都在等待。并发是最糟糕的。最后,读取提交和可重复读取。这两个隔离级别比较复杂,不仅要允许一定的并发量,还要解决问题。数据库的事务隔离越严格,并发的副作用越小,但代价越大;因为事务隔离的本质是让事务在一定程度上处于串行状态,这本身就与并发相矛盾。不同的应用程序具有不同级别的读取一致性和事务隔离。比如很多应用对数据一致性的要求就没有这么高。相反,它们对并发性有一定的要求。具体的隔离机制需要根据实际业务需求设置。和系统条件。对于幻读问题,可以通过在数据插入或更新时加乐观锁来解决数据写入失败的问题。4、事务隔离的实现了解了事务的隔离级别之后,我们来看看事务隔离是如何实现的。这里我们解释一下“可重复阅读”。在MySQL中,每条记录更新时,都会同时记录一次回滚操作。记录上的最新值,通过回滚操作,可以得到之前状态的值。假设一个值从1依次变为2、3、4,回滚日志中会有类似如下的记录。当前值为4,但是查询这条记录时,不同时间开始的事务会有不同的read-views。图中可以看到,在视图A、B、C中,这条记录的值分别是1、2、4。同一条记录在系统中可以有多个版本,这就是数据库的多版本并发控制(MVCC)。).对于read-viewA,要得到1,必须依次执行图中的所有回滚操作得到当前值。同时你会发现,即使另一个事务在把4改成5,这个事务也不会和read-viewA、B、C对应的事务冲突。你肯定会问,回滚日志不能永远保留,什么时候删除?答案是,不需要的时候删除。也就是说,系统会判断当没有事务需要使用这些回滚日志时,会删除回滚日志。什么时候不需要?也就是当系统中没有比这个回滚日志更早的read-view。基于上面的描述,我们来讨论一下为什么建议尽量不要使用长事务。长交易意味着系统中会有非常旧的交易视图。由于这些事务可能随时访问数据库中的任何数据,因此在事务提交之前,必须保留其在数据库中可能使用的回滚记录,这将导致大量的存储空间被占用。在MySQL5.5及之前的版本中,回滚日志与数据字典一起放在ibdata文件中。即使最后提交了长事务,清除了回滚段,文件也不会变小。我见过只有20GB数据和200GB回滚段的库。最后,我不得不重建整个库以清理回滚段。长事务除了对回滚段有影响外,还占用锁资源,可能会拖垮整个库。五、小结本文主要介绍了事务隔离相关的理论知识,以及围绕MySQL实现事务隔离。可能会有一些遗漏。欢迎网友们指出!参考1.csdn-技术搬砖人-Felix-事务隔离原理的实现与实现2.脏读、不可重复读、幻读详解