昨天接到阿里的电话面试,对方问了一个在MySQL当中,什么是幻读。当时一脸懵逼,凭着印象和对方胡扯了几句。面试结束后,赶忙去查资料,才发现以前对幻读的理解彻底错误。下面,咱们就聊聊幻读。面试
要说幻读,就要从MySQL的隔离级别提及。MySQL的4钟隔离级别分别是:数据库
在该隔离级别,全部事务均可以看到其余未提交事务的执行结果。本隔离级别不多用于实际应用,由于它的性能也不比其余级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。并发
脏读的具体示例以下:性能
时间点 | 事务A | 事务B |
---|---|---|
1 | 开启事务 | |
2 | 开启事务 | |
3 | 查询数据为100条 | |
4 | insert一条数据 | |
5 | 再查询,结果为101条 |
在时间点5,事务A再次查询数据时,事务B并无提交事务,可是,新的数据也被事务A查出来了。这就是脏读。排序
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它知足了隔离的简单定义:一个事务只能看见已经提交事务所作的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),由于同一事务的其余实例在该实例处理其间可能会有新的commit,因此同一select可能返回不一样结果。事务
时间点 | 事务A | 事务B |
---|---|---|
1 | 开启事务 | |
2 | 开启事务 | |
3 | 查询数据为100条 | |
4 | insert一条数据 | |
5 | 查询数据为100条 | |
6 | 提交事务 | |
7 | 查询数据为101条 |
咱们能够看到,事务B在提交事务以前,事务A的两次查询结果是一致的。事务B提交事务之后,事务A再次查询,查询到了新增的这条数据。在事务A中,屡次查询的结果不一致,这就是咱们说的“不可重复读”。it
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到一样的数据行。不过理论上,这会致使另外一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另外一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。table
上面这一段是MySQL官方给出的解释,听着云里雾里。“可重读”这种隔离级别解决了上面例子中的问题,保证了同一事务内,屡次查询的结果是一致的。也就是说,事务B插入数据提交事务后,事务A的查询结果也是100条,由于事务A在开启事务时,事务B插入的数据尚未提交。class
可是,这又引出了另一个状况,“幻读”。这个幻读我以前理解是有问题的,在面试时,被对方一顿质疑。如今咱们就看看幻读的正确理解:select
时间点 | 事务A | 事务B |
---|---|---|
1 | 开启事务 | |
2 | 开启事务 | |
3 | 查询数据“张三”,不存在 | |
4 | 插入数据“张三” | |
5 | 提交事务 | |
6 | 查询数据“张三”,不存在 | |
7 | 插入数据“张三”,不成功 |
事务A查询“张三”,查询不到,插入又不成功,“张三”这条数据就像幻觉同样出现。这就是所谓的“幻读”。网上对“幻读”仍是其余的解释,都是错误的。好比像“幻读”和“不可重复读”是同样,只不过“幻读”是针对数据的个数。这些理解都是错误的。
这是最高的隔离级别,它经过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每一个读的数据行上加上共享锁。在这个级别,可能致使大量的超时现象和锁竞争。这种隔离级别不多使用,不给你们作过多的介绍了。