脏读、不可重复读、幻读

2024-05-09  本文已影响0人  M_lear
  1. 脏读 (Dirty Read):
    脏读发生在一个事务读取了另一个事务尚未提交的数据。如果那个事务回滚,读取的数据就会变得不准确或错误。例如,事务 A 修改了一条记录但尚未提交,事务 B 在这时读取了同一记录,接着事务 A 回滚,那么事务 B 读到的数据就是不正确的。
  2. 不可重复读 (Non-repeatable Read):
    不可重复读发生在一个事务中多次读取同一数据集合时,由于其他事务的修改操作,导致两次读取的数据不一致。例如,事务 A 读取了一个记录,事务 B 更新了该记录并提交,当事务 A 再次读取同一记录时,发现数据已经发生变化。
  3. 幻读 (Phantom Read):
    幻读是指当一个事务重新执行一个范围查询时,返回一组符合查询条件的“幻影”数据。这是由于另一个并发事务在此期间插入或删除了满足查询条件的新行。例如,事务 A 根据某个条件查询数据行,然后事务 B 插入了一些新的符合条件的数据行并提交。当事务 A 重新执行相同的查询时,就会看到之前未出现过的新行。

解决这些问题的一种方法是设置合适的事务隔离级别。SQL 标准定义了四个隔离级别:读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。每个级别都能解决一部分并发问题,但是隔离级别越高,性能可能越受影响,因为系统必须做更多工作来保持事务的隔离。例如,可重复读可以防止不可重复读,而串行化则可以防止脏读、不可重复读和幻读。

在 MySQL 的 InnoDB 存储引擎中,默认的隔离级别是可重复读(Repeatable Read)。在 SQL 标准中,可重复读隔离级别不保证防止幻读,但 InnoDB 的实现对此有所扩展。InnoDB 的可重复读隔离级别通过使用一致性非锁定读(consistent nonlocking reads)和Next-Key Locks(锁定索引记录和间隙)确保了即使在并发环境中,同一个事务中的查询可以看到一致的数据快照,从而避免了不可重复读和幻读的问题。

在8.0.33版本上实测:
普通的范围select不会读取其他事务在范围内新增或删除的行。不会有幻读的问题。
加锁的范围select(select ... for update)会阻塞其他事务在范围内新增或删除行。不会有幻读的问题。

但是先普通范围select,再加锁范围select。第一次读不会读取其他事务在范围内新增或删除的行(读快照)。第二次读会读取到在此之前其他事务在范围内新增或删除的行(读最新已提交的数据)。会有两次读取数据不一致的问题。

上一篇 下一篇

猜你喜欢

热点阅读