那实际上,我们研究事务的原理,就是研究MySQL的InnoDB引擎是如何保证事务的这四大特性的。
我们在讲解事务原理的时候,主要就是来研究一下redolog,undolog以及MVCC。
某张表的一条数据如下
DB_TRX_ID : 代表最近修改事务 ID ,记录插入这条记录或最后一次修改该记录的事务 ID ,是自增的。DB_ROLL_PTR : 由于这条数据是才插入的,没有被更新过,所以该字段值为 null 。
同一事务或不同事务经过多次的对同一数据的操作形成如下的版本链
我们发现,不同事务或相同事务对同一条记录进行修改,会导致该记录的undolog生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。
MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种数据库管理系统中用来实现并发事务的技术。
1.当前读:读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select ... lock in share mode(共享锁),select ...for update、update、insert、delete(排他锁)都是一种当前读。
2.快照读:简单的select(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读
在测试中,我们看到即使事务B提交了数据,事务A中也查询不到。 原因就是因为普通的select是快照 读,而在当前默认的RR隔离级别下,开启事务后第一个select语句才是快照读的地方,后面执行相同的select语句都是从快照中获取数据,可能不是当前的最新数据,这样也就保证了可重复读。
隐藏字段
|
含义
|
DB_TRX_ID
|
最近修改事务 ID ,记录插入这条记录或最后一次修改该记录的事务 ID 。
|
DB_ROLL_PTR
|
回滚指针,指向这条记录的上一个版本,用于配合 undo log ,指向上一个版本。
|
DB_ROW_ID
|
隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段
|
而上述的前两个字段是肯定会添加的, 是否添加最后一个字段DB_ROW_ID,得看当前表有没有主键,如果有主键,则不会添加该隐藏字段。
字段
|
含义
|
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的版本链,从上到下进行挨个匹配:
在进行匹配时,会从undo log的版本链,从上到下进行挨个匹配: