简单说,读了一条未提交的数据
一个事务读取了另外一个事务修改后记录 强调的是 update 和delete ,只需要锁住满足条件的记录即可
一个事务读取了另外一个事务插入的数据,强调的是 insert ,要锁住满足条件及相近的记录。
MYSQL 中默认的隔离级别是可重复读,可解决脏读和不可重复读的问题。但是不能解决幻读的问题。 Oracle 默认的是Read Commit 读已提交,可以避免脏读的问题。
一般解决不可重复读和幻读问题,是采用锁机制实现,有没有一种乐观锁的问题去处理,可以采用 MVCC 机制的设计,可以用来解决这个问题。取代行锁,降低系统开销。
MVCC 的英文全称是 Multiversion Concurrency Control ,中文意思是多版本并发控制技术。原理是,通过数据行的多个版本管理来实现数据库的并发控制,简单来说就是保存数据的历史版本。可以通过比较版本号决定数据是否显示出来。读取数据的时候不需要加锁可以保证事务的隔离效果。
快照读,读取的是快照数据,不加锁的简单 Select 都属于快照读.
SELECT * FROM player WHERE ...
当前读就是读的是最新数据,而不是历史的数据,加锁的 SELECT,或者对数据进行增删改都会进行当前读。
SELECT * FROM player LOCK IN SHARE MODE;
SELECT FROM player FOR UPDATE;
INSERT INTO player values ...
DELETE FROM player WHERE ...
UPDATE player SET ...
InnoDB 是如何存储记录多个版本的?这些数据是 事务版本号,行记录中的隐藏列和Undo Log。
每开启一个日志,都会从数据库中获得一个事务ID(也称为事务版本号),这个事务 ID 是自增的,通过 ID 大小,可以判断事务的时间顺序。
InnoDB 将行记录快照保存在 Undo Log 里。
Undo Log
数据行通过快照记录都通过链表的结构的串联了起来,每个快照都保存了 trx_id 事务ID,如果要找到历史快照,就可以通过遍历回滚指针的方式进行查找。
如果一个事务要查询行记录,需要读取哪个版本的行记录呢?Read View 就是来解决这个问题的。Read View 可以帮助我们解决可见性问题。Read View 保存了当前事务开启时所有活跃的事务列表。换个角度,可以理解为: Read View 保存了不应该让这个事务看到的其他事务 ID 列表。
Read View
如果当前事务的 creator_trx_id 想要读取某个行记录,这个行记录ID 的trx_id ,这样会有以下的情况:
InnoDB 实现多版本控制 (MVCC)是通过 ReadView+ UndoLog 实现的,UndoLog 保存了历史快照,ReadView 规则帮助判断当前版本的数据是否可见。