MySQL可重复读取隔离级别和丢失更新现象

时间:2018-11-30 18:17:41

标签: mysql database relational-database repeatable-read

High Performance Java Persistence书的6.3.3.3节中,写道,“ MySQL可重复读取”隔离级别中可能会出现“丢失更新”现象。这是屏幕截图:

enter image description here

假设以下内容(隔离级别为REPEATABLE READ):

              tx1                     |                tx2
-----------------------------------------------------------------------------------
START TRANSACTION;                    |
SELECT * FROM test WHERE id = 1;      |
( say, DB_TRX_ID = 7 at this moment)   |
                                      |
                                      |  START TRANSACTION;
                                      |  SELECT * FROM test WHERE id = 1;
                                      |  UPDATE test SET name="x" WHERE id = 1;
                                      |  COMMIT;(say, makes DB_TRX_ID = 10)
                                      |
UPDATE test SET name="y" WHERE id = 1;|
COMMIT;

问题:

在tx1提交后,MVCC将检测到行版本(DB_TRX_ID)不再等于7(而不是10)并执行回滚吗?否则,提交将成功,导致更新丢失?

1 个答案:

答案 0 :(得分:1)

  

在“可重复读取”隔离级别中,MySQL MVCC是否应使用数据库级别的悲观锁定来防止丢失更新,从而导致事务回滚?

根据SQL标准,“可重复读取”应防止:

  • 脏读
  • 不可重复读取

该标准对丢失的更新一无所知,因为该标准是在2PL (Two-Phase Locking)是事实COncurrency Control机制时设计的。

如果使用2PL,那么“可重复读取”隔离级别实际上将防止出现Lost Update

但是,MVCC可以通过多个版本的元组提供可重复读取,但是,为了防止丢失更新,它们还需要事务调度程序来跟踪对特定事务读取的记录的元组修改。显然,InnoDB不能那样工作。

  

MySQL MVCC不应使用数据库级悲观锁定来防止丢失更新,从而导致事务回滚

现在,如果您仔细阅读High-Performance Java Persistence book中的“交易”一章,您会发现MVCC在可重复读取中不使用任何悲观锁定。唯一采取的锁定是对聚集索引采取的间隙和下一键锁定,但是这些不能防止丢失更新。

MySQL仅将悲观锁定用于可序列化,即使使用基于MVCC_的InnoDB存储引擎,它也提供2PL并发控制模型。