当前读和快照读
当前读
- select ... lock in share mode(共享锁)
- select ...for update、update、insert、delete(排他锁)
快照读
- RC隔离级别:每次执行select,都生成一个新的Read View,每次读取的数据都是最新数据
- RR隔离级别:开启事务后第一个执行的select语句生成Read View,后面执行select都是使用第一次的Read View,读取的数据可能不是最新数据,实现了可重复读
- 串行化隔离界别:快照读会退化为当前读(不存在多事务并发执行,所有读写都加表锁)
数据库并发场景有三种
-
读-读
:不存在任何问题,也不需要并发控制 -
读-写
:有线程安全问题,可能造成事务隔离性问题,有脏读,幻读,不可重复读问题(MVCC针对读写并发问题) -
写-写
:有线程安全问题,可能会存在更新丢失问题
MVCC
多版本并发控制( Multi-Version Concurrency Control )
- MVCC的实现依赖于三个隐藏字段、undo log和Read View来实现。
- MVCC只存在于 RR 和 RC这两个隔离级别下。
聚集索引记录三个隐藏列
事务ID:每个事务开启时,都会被分配一个事务ID, 这个ID是递增的,所以最新的事务,ID值越大
-
DB_ROW_ID:隐藏主键,如果表没有指定主键,将会生成该隐藏字段(指定主键就不会添加该字段)
-
DB_TRX_ID:最近修改事务ID,记录插入该记录或最后一次修改该记录的事务ID
-
DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本的记录
undo log版本链
介绍
不同事务或相同事务对同一条记录进行修改,会导致该记录的undo log生成一条记录版本链表,链表的头部是最新记录,链表尾部是最早的旧记录(使用头插法插入数据)
undo log日志(回滚日志)
在执行insert/update/delete时产生的便于数据回滚的日志,存储着修改数据的反向操作(逻辑日志)
有两个作用:事务回滚、MVCC(undo log版本链)
- insert:产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除(还有活动的事务正在使用则不会删除)
- update/delete:产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即删除。
undo log版本链的生成
id | age | name | DB_TRX_ID | DB_ROLL_POINT |
30 | 30 | A30 | 1 | null |
事务1 | 事务2 | 事务3 |
---|---|---|
开启事务 | 开启事务 | 开启事务 |
修改id=30的记录,age为3 | 查询id为30的记录 | |
提交事务 | 修改id为30的记录,name为A3 | |
提交事务 | ||
修改id=30的记录,age为10 | ||
查询id为30的记录 | ||
提交事务 | ||
![](https://img-blog.csdnimg.cn/98f3d837c8ed4db998fa8e9cd39213e2.png)
![](https://img-blog.csdnimg.cn/25f7f53798ef4a4ca3db51ed264ef916.png)
Read View
Read View 介绍
Read View作用:决定快照读时,读取undo log版本链中的哪一个条记录
Read View是事务进行快照读操作时产生的读视图,记录并维护了当前活跃(未提交)的事务ID
生成ReadView的时机
- RC:在事务中每一次执行快照读时生成ReadView。
- RR:仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。
ReadView的核心字段
字段 | 含义 |
---|---|
m_ids | 当前活跃的事务ID集合 |
min_trx_id | 最小活跃事务ID |
max_trx_id | 预分配事务ID,当前最大事务ID + 1(因为事务ID是自增的) |
creator_trx_id | ReadView创建者的事务ID |
条件 | 条件 | 说明 |
---|---|---|
trx_id==creator_trx_id
| 可以访问该版本 |
数据是当前这个事务更改的
|
trx_id < min_trx_id | 可以访问该版本 | 数据已经提交了 |
trx_id > max_trx_id | 不可以访问该版本 | 该事务是在ReadView生成后才开启 |
min_trx_id<= trx_id<=max_trx_id |
如果trx_id不在m_ids中,可以访问该版本
| 如果条件成立,数据已经提交 |
如果undo log版本链的头节点记录,四个条件判断后的结果都是不可访问,则根据回滚指针找到上一个版本的记录,继续判断,直到找到一个可以访问的记录。
RC和RR都是使用这个规则,只不过RC每次快照读都产生新Read View,而RR只会产生一次。
RC和RR级别快照读的不同
RC:读已提交
RR:可重复读
RC和RR区别是生成ReadView策略不同,从而导致RC、RR级别下快照读的结果不同
-
RC:每次快照读都会生成最新的的ReadView(提交的事务修改的数据一定能看到)
-
RR:同一个事务在第一次快照读的时候生成一个ReadView,之后的快照读都复用之前的ReadView