幻读,脏读,不可重复读

img

三种读

  • 脏读:读到事物未提交的数据
  • 不可重复度:俩次读取数据不一样,中间有事物进行了更新操作
  • 幻读:读取俩次数据,第二次读取多了数据,中间有事物进行了插入操作

MYSQL默认隔离级别:重复度

MVCC 多版本控制

三种关键:隐藏字段,undo_log,ReadView

隐藏字段:当前事物id,回滚指针指向undo_log

undo_log: 记录数据的历史版本,形成undo_log链

read_view: 读快照,读已提交的隔离级别每次读取都创建一个,可重复读隔离级别在事务开始时创建一个,事务期间一直使用这个read_view

读数据过程

  1. 读取数据时,构建read_view
  2. 根据read_view判断数据版本是否可见
  3. 可见则读取数据,不可见则根据回滚指针找到undo_log链,找到可见版本读取

规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 查询
// 根据ReadView判断可见版本
// 检查数据行的tx_id
// 如果tx_id 小于 min_trx_id 则该行数据是在readview创建前提交的,事务可见
// 如果tx_id 大于 max_trx_id 则该行数据是在readview创建后才开始的,事务不可见
// 如果tx_id 在min_trx_id 和 max_trx_id 之间,则检查tx_id是否在m_ids中, 如果在则说明该事务还未提交,事务不可见,否则可见
let is_visible = |tx_id: u64, read_view: &ReadView| {
if tx_id < read_view.min_trx_id {
true
} else if tx_id > read_view.max_trx_id {
false
} else {
//这里不满足上面的两个条件,说明tx_id在min和max之间
!read_view.m_ids.contains(&tx_id) //不在read_view的活跃事务列表中,则可见
}
};