1、mvcc 多版本控制(可重复读隔离级别)
在Mysql中MVCC是在Innodb存储引擎中得到支持的,Innodb为每行记录都实现了三个隐藏字段:
(1)、事务ID(DB_TRX_ID 6-byte ):最新插入或修改行的事务ID,删除是特殊的修改,会有1bit标示;InnoDB内部维护了一个递增的tx id counter,其当前值可以通过show engine innodb status获得
(2)、回滚指针(DB_ROLL_PTR 7-byte):指向回滚日志的undo log
(3)、隐藏的ID 6-byte
![image.png](https://static.studygolang.com/180928/447becae50d66a1290338e931ff53172.png)
当事务更改某行的值时,操作如下:
(1)、用排他锁锁定该行
(2)、记录redo log
(3)、把该行修改前的值Copy到undo log
(4)、修改当前行的值,填写事务编号,使回滚指针指向undo log中的修改前的行
![image.png](https://static.studygolang.com/180928/28b21afcddb49c9e056e7b68233bcc47.png)
(5)、如果事务1最后执行COMMIT操作,则什么操作都不用做。如果执行ROLLBACK操作,则需要通过回滚指针从undo log中还原修改前的数据。
(6)、释放该行的排它锁
=====================================================================
read view 判断当前版本数据项是否可见:
在InnoDB中,创建一个新事务的时候,InnoDB会将当前系统中的活跃事务列表(trx_sys->trx_list)创建一个副本(read view),副本中保存的是系统当前不应该被本事务看到的其他事务id列表。
当用户在这个事务中要读取该行记录的时候,InnoDB会将该行当前的版本号与该read view进行比较。
注:新建事务(当前事务)与正在内存中commit 的事务不在活跃事务链表中。
函数:read_view_sees_trx_id。
read_view中保存了当前全局的事务的范围:【low_limit_id, up_limit_id】
1. 当行记录的事务ID小于当前系统的最小活动id,就是可见的。
if (trx_id < view->up_limit_id) {
return(TRUE);
}
2. 当行记录的事务ID大于当前系统的最大活动id(也就是尚未分配的下一个事务的id),就是不可见的。
if (trx_id >= view->low_limit_id) {
return(FALSE);
}
3. 当行记录的事务ID在活动范围之中时,判断是否在活动链表中,如果在就不可见,如果不在就是可见的。
for (i = 0; i < n_ids; i++) {
trx_id_t view_trx_id
= read_view_get_nth_trx_id(view, n_ids - i - 1);
if (trx_id <= view_trx_id) {
return(trx_id != view_trx_id);
}
}
理想状态下,事务1的事务id=1,事务2的事务id=2。因为事务2执行时查询时,事务1正处于事务执行状态。
所以read view为{1},事务2读取的数据行 trx_id=1,read view中最早的事务id为trx_id_min=1, 最迟的事务id为trx_id_max=1。
因为trx_id_min <= trx_id <= trx_id_max,并且trx_id_min = trx_id = trx_id_max,说明该行记录所在事务在本次新事务创建的时候处于活动状态,不可见。
所以从该行记录的DB_ROLL_PTR指针所指向的回滚段中取出最新的undo-log的版本号的数据,将该可见行的值返回。所以不会出现脏读的现象。
=====================================================================
InnoDB行锁:
是通过索引上的索引项来实现的,通过在数据中对相应数据行加锁来实现的。
InnoDB这种行锁实现特点意味者:只有通过索引条件检索数据,InnoDB才会使用行级锁,否则,InnoDB将使用表锁!
Mysql中的间隙锁:
1、间隙划分;
2、间隙锁锁定区域,根据检索条件向左寻找最靠近检索条件的记录值A,作为左区间,向右寻找最靠近检索条件的记录值B作为右区间,即锁定的间隙为(A,B);
3、间隙锁的目的是为了防止幻读:
(1)防止间隙内有新数据被插入;
(2)防止已存在的数据,更新成间隙内的数据(例如防止numer=3的记录通过update变成number=5);
4、nnodb自动使用间隙锁的条件:
(1)必须在RR级别下;
(2)检索条件必须有索引(没有索引的话,mysql会全表扫描,那样会锁定整张表所有的记录,包括不存在的记录,此时其他事务不能修改不能删除不能添加);
有疑问加站长微信联系(非本文作者))