在High Performance Java Persistence书的6.3.3.3节中,写道,“ MySQL可重复读取”隔离级别中可能会出现“丢失更新”现象。这是屏幕截图:
假设以下内容(隔离级别为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)并执行回滚吗?否则,提交将成功,导致更新丢失?
答案 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并发控制模型。