当前位置: 首页 > 后端技术 > Java

面试官:说说MySQL的事务隔离级别?

时间:2023-04-01 14:02:48 Java

MySQL事务隔离级别是为了解决并发事务相互干扰的问题。MySQL事务隔离级别有四种:READUNCOMMITTED:读未提交。READCOMMITTED:读取已提交。REPEATABLEREAD:可重复读。SERIALIZABLE:序列化。1.四种事务隔离级别1.1READUNCOMMITTED未提交读,又称未提交读,处于该隔离级别的事务可以看到其他事务中未提交的数据。这个隔离级别可以读取到其他事务中未提交的数据,而未提交的数据可能会被回滚,所以我们称这个级别读取的数据为脏数据,这种问题称为脏读。1.2READCOMMITTED读提交,也叫提交读,这种隔离级别的事务可以读取提交事务的数据,所以不会有脏读问题。但是,由于在事务执行过程中可以读取其他事务提交的结果,所以同一个SQL查询在不同的时间可能会得到不同的结果。这种现象称为不可重复读。1.3REPEATABLEREAD可重复读,MySQL默认的事务隔离级别。可重复读可以解决“不可重复读”的问题,但是仍然存在幻读问题。所谓幻读,就是当同一个事务在不同的时间使用同一个SQL查询时,会产生不同的结果。例如,执行两次但第二次返回第一次未返回的行的SELECT是“幻像”行。注:幻读和不可重复读的侧重点不同。不可重复读侧重于数据修改,同一行数据两次读取不同;幻读侧重于增删改查,两次查询返回的数据行数不同。1.4SERIALIZABLE序列化,事务的最高隔离级别,它会强制事务进行排序,这样就不会发生冲突,从而解决脏读、不可重复读和幻读的问题,但是由于执行效率低,实际使用场景并不多。1.5总结简单概括一下,MySQL中的事务隔离级别就是为了解决脏读、不可重复读、幻读等问题。这四种隔离级别与这三种问题的对应关系如下:事务隔离级别脏读不可重复读幻读读未提交(READUNCOMMITTED)√√√读已提交(READCOMMITTED)×√√可重复读(REPEATABLEREAD)××√序列化(SERIALIZABLE)×××2.并发事务中存在的问题并发事务中存在以下三个问题。2.1脏读一个事务读取另一个事务保存的commit数据,然后事务回滚,导致第一个事务读取了一个不存在的脏数据。2.2不可重复读在同一个事务中,同一个查询在不同的时间得到不同的结果。例如事务在T1读取了某行数据,在T2再次读取该行时,该行的数据已经被修改,所以再次读取时,与T1查询得到的结果不同.2.3幻读MySQL对幻读的定义如下:当同一个查询在不同的时间产生不同的行集合时,就会在一个事务中发生所谓的幻读问题。例如,如果SELECT执行两次,但第二次返回第一次未返回的行,则该行是“幻像”行。官方文档:https://dev.mysql.com/doc/ref...翻译成中文是:同一个查询在不同的时间得到不同的结果,这就是事务中的幻读问题。例如,执行两次但第二次返回第一次未返回的行的SELECT是“幻像”行。3.隔离级别实践3.1查询事务隔离级别查看全局MySQL事务隔离级别和当前session的事务隔离级别的SQL如下:select@@global.tx_isolation,@@tx_isolation;以上SQL执行结果如下图所示:3.2设置事务隔离级别每个连接MySQL的客户端都可以单独设置事务的隔离级别。MySQL可以使用如下SQL设置当前连接(客户端)的事务隔离级别:setsessiontransactionisolationleveltransactionisolationlevel;其中,事务隔离级别有4个值:READUNCOMMITTEDREADCOMMITTEDREPEATABLEREADSERIALIZABLE3.3脏读问题一个事务读取另一个事务保存的数据进行commit,然后事务回滚,导致第一个事务读取了一个非-存在脏数据。接下来,我们使用SQL来演示脏读问题。在正式开始之前,先创建一张测试表:--创建一个城市表droptableifexistscity;创建表城市(idintprimarykeyauto_increment,namevarchar(250)notnull);脏读执行顺序如下:dirtyread执行SQL及执行顺序如下:客户端A:setsessiontransactionisolationlevelreaduncommitted;客户A:开始交易;客户B:开始交易;客户端B:insertintocity(name)values('Xi'an');客户端A:select*fromcity;客户端B:回滚;客户A:从城市中选择*;事务隔离级别提交后,客户端A可以读取其他事务未提交的数据。当其他事务回滚时,客户端A读取的数据就变成了脏数据。这是脏读,即读取未提交的数据。已提交事务隔离级别存在脏读问题。3.4不可重复读问题在同一个事务中,同一个查询在不同的时间得到不同的结果。例如事务在T1读取了某行数据,在T2再次读取该行时,该行的数据已经被修改,所以再次读取时,与T1查询得到的结果不同.不可重复读的执行顺序如下:不可重复读SQL的执行顺序如下:clientA:setsessiontransactionisolationlevelreadcommitted;客户A:开始交易;客户A:select*fromcitywhereid=1;客户B:开始交易;ClientB:updatecitysetname='Chang'an'whereid=1;客户B:提交;客户端A:select*fromcitywhereid=1;对应的执行结果如下图所示:从上面的结果可以看出,客户端A设置读取已提交事务隔离级别后,使用同一条SQL读取两次相同的数据内容为不同,这意味着它不能被重复读取。即在读提交事务隔离级别,可能存在不可重复读问题。3.5幻读问题同一个查询在不同的时间得到不同的结果,这就是事务中的幻读问题。例如,执行两次但第二次返回第一次未返回的行的SELECT是“幻像”行。幻读的执行顺序如下:幻读的SQL和执行顺序如下:ClientA:setsessiontransactionisolationlevelrepeatableread;客户A:开始交易;客户端A:从id<5的城市中选择;--查询1数据ClientB:开始交易;客户端B:insertintocity(id,name)values(2,'北京');客户B:提交;客户端A:updatecitysetname='北京'whereid=2;客户端A:从id<5的城市中选择;--查询对应执行的2条数据的结果如下图所示:从上面的结果可以看出,客户端A设置为可重复读事务隔离级别后,使用相同的SQL来查询相同的结果。第一个查询产生一条数据,第二个查询产生两条数据。多出的一行数据称为“幻读”行,因此我们可以得出这样的结果,即可重复读可能存在幻读问题。总结MySQL中有四种事务隔离级别:未提交读(脏读/不可重复读/幻读问题)、已提交读(不可重复读/幻读问题)、可重复读(幻读问题)和序列化,其中可重复读是MySQL默认的事务隔离级别。脏读读取其他事务未提交的数据,不可重复读读取其他事务修改的数据,幻读读取其他事务添加或删除的“幻象”行数据。