mvcc (多版本并发控制),开启多个事务,并基于快照读Read View实现;
Read View几个属性
trx_ids: 当前系统活跃事务版本号集合;
low_limit_id: 创建当前read view 时, 系统最大事务版本号+1;
up_limit_id: 创建当前read view 时, 活跃事务最小版本号;
creator_trx_id: 创建当前read view的事务版本号;
read_view 可见性规则:
1.数据事务ID小于read view中的最小活跃事务ID,即trx_id<up_limit_id,
说明数据是在当前事务生成read view之前就已经存在了,则显示
2.数据事务ID大于或等于read view 中的当前系统的最大事务ID,即trx_id>low_limit_id,
说明该数据是在当前read view 创建之后才产生的,则不显示
3.trx_id = creator_trx_id,是本事务产生的数据,则显示
4.被访问版本的trx_id,在readview的min_trx_id和max_trx_id之间,则需要判断trx_id值是否在m_ids列表中
如果在:说明创建readview时,该版本的事务还未提交,通过回滚指针查找历史版本并返回;
如果不在:说明创建readview时,该版本的事务已经提交,所以直接返回该版本的数据
结合具体列子,
准备一张表,字段为id,age,当我们插入一条数据的时候,mysql会增加几个隐藏字段,不会展示给我们用户,其中一个字段为事务id,即trx_id
准备三个事务,分别更新数据,trx_id是隐藏的,这里列出来方便说明
id | age | trx_id | point | |
事务1 | 1 | 1 | 1 | 指针 |
事务2 | 1 | 2 | 2 | 指针 |
事务3 | 1 | 3 | 3 | 指针 |
注:这个不是表数据,事务提交或者回滚后,只有一条
首先,开启事务1,插入一条数据id=1,age=1 这时隐藏列trx_id的值假如为1,以后的事务在此基础上依次增长,提交事务,这时数据库里就有一条数据了。
情景1
开启事务2,执行查询操作,
那么trx_id=2,mysql会记录开启是这个事务时的事务数据,包括目前存活的事务id列表trx_ids,值为2
最大事务id ,活跃的最大事务id+1,low_limit_id 为3;
最小事务id,up_limit_id 为2;
自己的事务版本,creator_trx_id为2
开启事务2执行查询全表的操作,表中生成id为1的数据的事务id为1,即trx_id 1<2,显示id=1的这条数据;
情景2
开启事务2,事务执行查询之前,开启了事务3,并更新为id=1,age=3,提交完成,此时事务2查询,id=1的这条数据的trx_id为3,即trx_id 3>=3,不会显示age=3的这条数据,通过回滚直接读取历史版本,显示age为1的数据
情景3
开启事务2,事务3,事务3执行更新,未提交,
事务2执行查询操作,活动的事务trx_ids列表为(2,3),low_limit_id为4,up_limit_id为2
age为3的记录的trx_id处于 2 <= 3 <4,3在 trx_ids中,不显示这个版本的数据;
情景4
开启事务2,事务3,事务3执行更新并提交,
事务2执行查询操作,活动的事务trx_ids列表为(2),low_limit_id为4,up_limit_id为2
age为3的记录的trx_id处于 2 <= 3 <4,3不在 trx_ids中,显示这个版本的数据;