日期:2014-05-16 浏览次数:20417 次
??? 通过为每一行记录添加两个额外的隐藏的值来实现MVCC,这两个值一个记录这行 数据何时被创建,另外一个记录这行数据何时过期(或者被删除)。
??? 但是InnoDB并不存储这些事件发生时的实际时间,相反它只存储这些事件发生时的系统版 本号。这是一个随着事务的创建而不断增长的数字。每个事务在事务开始时会记录它自己的系统版本号。每个查询必须去检查每行数据的版本号与事务的版本号是否 相同。
??? 让我们来看看当隔离级别是REPEATABLE READ时这种策略是如何应用到特定的操作的: SELECT InnoDB必须每行数据来保证它符合两个条件:
??? 1、InnoDB必须找到一个行的版本,它至少要和事务的版本一样老(也即它的版本号不大于事务的版本号)。这保证了不管是事务开始之前,或者事务创建时,或者修改了这行数据的时候,这行数据是存在的。
??? 2、这行数据的删除版本必须是未定义的或者比事务版本要大。这可以保证在事务开始之前这行数据没有被删除。
符合这两个条件的行可能会被当作查询结果而返回。
??? INSERT:InnoDB为这个新行记录当前的系统版本号。
??? DELETE:InnoDB将当前的系统版本号设置为这一行的删除ID。
??? UPDATE:InnoDB会写一个这行数据的新拷贝,这个拷贝的版本为当前的系统版本号。它同时也会将这个版本号写到旧行的删除版本里。
??? 这种额外的记录所带来的结果就是对于大多数查询来说根本就不需要获得一个锁。他们只是简单地以最快的速度来读取数据,确保只选择符合条件的行。
??? 这个方案的缺点在于存储引擎必须为每一行存储更多的数据,做更多的检查工作,处理更多的善后操作。
??? MVCC维持一个数据的多个版本使读写操作没有冲突
?
??? 开始时对版本号的比较不是太明白,后来想了想大概是这么一回事:因为事务A更新(update,delete,insert)时被改动的那一行的版本都会重新标记为与它所在事务A一样,因此如果这个事务执行期间,有另一个事务B(B事务执行时间早于A因此B的版本号小于A)该行操作(select)就会出现B的版本号比该行的版本号“老”(小),因此改动的行不会被选出,而选出旧版本的行。
?