MVCC
一些隐藏字段
DB_ROW_ID用于存储删除版本号
DB_TRX_ID用于存储事务ID
DATA_ROLL_PTR指向UNDO LOG RECORD,UNDO LOG RECORD拥有更新之前的所有数据
创建时间(版本号)
删除时间(版本号)
操作
新增
创建时间DB_TRX_ID
删除时间未定义
修改
复制一行作为新行
创建时间DB_TRX_ID
删除时间未定义
旧行
修改删除时间为DB_TRX_ID
删除
修改删除时间为DB_ROW_ID
查询
不做任何修改,只读
原理
新增
保存当前的事务ID作为当前行的版本号
修改
复制一行新数据,新行的版本号为系统版本号,旧行数据的删除版本号为系统版本号
删除
修改删除行的删除版本号为当前系统版本号
查询
行版本号小于等于当前系统版本号
删除版本要么没定义或者大于当前系统版本号
另外
怎么保证先建立的事务又为提交的修改数据,不被后建立的事务读取呢?根据READ VIEW,每当开启一个事务时,把当前活动的事务都复制进READ VIEW列表。
事务隔离级别(transction isolation level) select @@tx_isolation;
未提交读(RU)
READ UNCOMMITED
指的是在事务未提交之前的数据库操作,其他事务也可以读取,会造成脏读。
例如:
事务A开启事务->事务B开启事务->事务B修改数据->事务A查询数据会得到B修改后的数据
提交读(RC)
READ COMMITED
指的是在事务未提交之前的数据库操作,其他事务不可以读取,不会脏读,但是会造成不可重复读。
例如:
事务A开启事务->事务B开启事务->事务B修改数据->事务A查询数据不会得到B修改后的数据->事务B提交事务->->事务A查询数据会得到B修改后的数据(不可重复读)
可重复读(RR)
REPEATABLE READ
基于行排它锁和MVCC,解决了不可重复读的问题,但是会造成幻读。
例如:
事务A开启事务->事务B开启事务->事务B新增数据->事务A查询数据不会得到B新增后的数据->事务A新增数据会提示主键冲突(幻读)
串行化SERIALIZABLE
强制加锁串行话,避免幻读的问题,但是会导致大量的超时和锁争用的问题,一般用不上。