MySQL-事务隔离-幻读

有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top

全网最细面试题手册,支持艾宾浩斯记忆法。这是一份最全面、最详细、最高质量的 java 面试题,不建议你死记硬背,只要每天复习一遍,有个大概印象就行了。 https://store.amazingmemo.com/chapterDetail/1685324709017001


1. 什么是幻读?

幻读是指在事务并发执行过程中,某个事务在读取某个范围的数据时,另一个事务在该范围内新增或删除了数据,导致前一个事务再次读取时,出现了前后两次读取结果不一致的情况。

2. 为什么会出现幻读?

幻读的出现主要是因为事务隔离级别造成的。

在读已提交(Read Committed)和可重复读(Repeatable Read)隔离级别下,事务在读取数据时会加锁,防止其他事务对其进行修改或删除。但是对于新增数据来说,并不受到加锁的限制,因此,当某个事务在读取数据时,另一个事务新增了符合该范围的数据,就会导致前一个事务再次读取时,出现了新增数据的“幻象”。

3. 幻读的实现原理?

幻读的实现主要依赖于数据库的行级锁。

在读已提交隔离级别下,数据库对被读取的数据行进行行级锁定,防止其他事务对其进行修改或删除。但是对于新增数据来说,并不受到行级锁的限制,因此,当某个事务在读取数据时,另一个事务新增了符合该范围的数据行,就会导致前一个事务再次读取时,出现了新增数据行的“幻象”。

4. 幻读的使用示例

假设有一个订单表,多个事务同时向该表插入数据,并且一个事务要求查询订单表中某个时间范围内的数据。

示例代码如下:

// 查询某个时间范围内的订单
@Transactional(isolation = Isolation.READ_COMMITTED) public List<Order> getOrdersByTimeRange(Date startTime,Date endTime){
        // 执行查询语句
        List<Order> orders=orderMapper.getOrdersByTimeRange(startTime,endTime);
        return orders;
        }

在上述代码中,假设有两个事务同时执行 getOrdersByTimeRange 方法,一个事务查询了范围为 2021-01-01 到 2021-01-31 的订单,而另一个事务在该范围内新增了一条订单数据。当第一个事务再次查询时,就会发现出现了新增的订单数据,导致了幻读现象。

5. 幻读的优点

幻读虽然在一定程度上提高了数据的一致性,但在某些场景下也可能带来一些优势,比如:

  • 提供了更准确的数据。通过幻读,事务能够获取最新的数据情况,避免了因为读取的是旧数据而导致的错误判断。

6. 幻读的缺点

幻读也存在一些缺点,包括:

  • 降低了并发性能。由于幻读需要进行额外的锁操作,会降低系统的并发性能。

  • 增加了数据不确定性。由于幻读可能出现在事务的读取过程中,会导致前后两次读取结果不一致,增加了数据的不确定性和操作的风险。

7. 幻读的使用注意事项

在开发中,为了避免幻读问题,可以采取以下措施:

  • 尽量使用更高的事务隔离级别,比如可串行化(Serializable)隔离级别。

  • 使用行级锁或间隙锁来解决幻读问题。

  • 合理设计事务边界,减少事务的隔离范围。

8. 总结

幻读是指在事务并发执行过程中,某个事务在读取某个范围的数据时,另一个事务在该范围内新增或删除了数据,导致前一个事务再次读取时,出现了前后两次读取结果不一致的情况。幻读的出现主要是因为事务隔离级别造成的,依赖于数据库的行级锁来实现。幻读虽然在某些场景下提供了更准确的数据,但也降低了并发性能并增加了数据不确定性。为避免幻读问题,可以采取使用更高的事务隔离级别、行级锁或间隙锁以及合理设计事务边界等措施。

最后更新于