MVCC(多版本并发控制):为了解决数据库并发读写和数据一致性的问题,是一种思想,可以有多种实现方式。
核心思想:写入时创建行的新版本,读取时查看当前行版本。
InnoDB解决方法思路:undo log+read view
trx_id:表示最近修改该行的事务id。
roll_pointer:指向的是上一个版本数据地址。
trx_id:每次开启一个事务时,事务都有一个id,如果事务对行进行了修改,同时修改行的trx_id为当前事务的id。
roll_pointer:事务对行进行了修改,同时将历史版本数据写入undo log,并修改roll_pointer指针指向修改前的版本。
举例:使用更新语句更新表中内容。
update users set age = 30 where id = 1;
update users set age = 40 where id = 1;
undo是一种逻辑日志,主要在事务的执行过程中,记录数据修改的历史版本,在必要的时候恢复到历史的状态。这些连接的版本数据称为版本链。
undo的回滚方式:如果要将数据回归为历史的版本,InnoDB做的是与之前相反的工作,对于insert,InnoDB会执行一个delete。对于delete,InnoDB会执行一个insert。对于update,会执行一个相反的update。
随着版本链的增长,事务读取的时候可以读取哪一个版本呢?这将是我们接下来要解决的问题。
什么时候生成Read View:在READ COMMITTED隔离级别下,每次读取数据时都会生成一个新的Read View。而在REPEATABLE READ隔离级别下,只有在事务中的第一个SELECT操作(快照读)时才会创建Read View,之后的SELECT操作不会再创建新的Read View。
Read View的几个属性:
读取数据过程:
快照读:实现是基于Read View。
当前读:始终读取的是最新的数据。
对于部分场景解决了幻读问题,部分场景没有解决。如果仅仅是查询操作的话可以解决幻读(快照读),如果是对新插入的数据进行更新(当前读),就会发生幻读。
MVCC只在RC(READ COMMITED)和RR(READ REPEATABLE )中生效,因为READ UNCOMMITED读取的永远都是最新数据,SERIALIZABLE会对读取的行加锁,不需要解决并发和数据一致性问题。
参考书籍:
[1]High Performance MySQL[M].,:792.
[2]MySQL技术内幕[M].,:391.