(1)简述:
ReadView机制就是 你执行一个事务的时候,生成一个ReadView,里面有4个关键属性:
m_ids,就是说有哪些事务在MySQL里执行还没提交的 是个列表 —> 活跃列表
min_trx_id,就是m_ids里最小的值
max_trx_id, MySQL下一个要生成的事务id,最大事务id 最大id+1
creator_trx_id,这个事务的id
举例:
假设数据库里有一条数据,很早之前插入的,事务id是32,此时两个事务并发执行,一个是事务A(id=45),一个是事务B(id=59),事务B 更新这行数据,事务A是去 读取这行数据的值,现在事务A直接开启一个ReadView,这个ReadView里的m_ids包含事务A和事务B的两个id,45和59,然后min_trx_id是45,max_trx_id是59+1=60 ,creator_trx_id是45是事务A自己,这个时候事务A第一次查询这行数据,会走一个判断,就是判断当前这行数据的trx_id是否小于ReadView中的min_trx_id,此时发现trx_id是32,是小于ReadView里的min_trx_id=45,说明事务开启之前,修改这行数据的事务就提交了,所以此时可以查到这行数据。
接着事务B将这行数据的值修改为了B,然后这样数据的trx_id设置为自己的id,就是59,同时roll_pointer指向了修改之前生成的一个undo log,接着这个事务B就提交了。
这个时候事务A再次查询,查询的时候会发现一个问题,此时数据行里的trx_id=59,这个trx_id是大于ReadView里的min_trx_id(45),同时小于ReadView里的max_trx_id(60)的,说明更新这条数据的事务,很可能跟事务A差不多同时开启的,于是会看下这个trx_id=59是否在 ReadView的 m_ids 列表里,在ReadView列表里有45和59两个事务id,直接证实,这个修改数据的事务是跟自己同一时段并发执行然后提交的,所以这行数据是不能查询的。
既然这行数据不能查询,那查什么?
顺着这条数据的 roll_pointer 的undo log日志链条往下找,就会找到最近的一条undo log,trx_id是32,此时发现trx_id=32,小于ReadView里的min_trx_id(45),说明这个 undo log版本必然是在事务A开启之前就执行且提交的。那这就查询最近的undo log里的值就好了。这就是undo log多版本链条的作用,可以保存一个快照链条读到之前的快照值。
通过这套ReadView+undo log日志链条的机制可以保证多事务并发执行是,事务A不会读到并发执行的事务B更新的值,只会读到之前最早的值。
接着假设事务A自己更新了这行数据的值,改成值A,trx_id修改为45,同时保存之前事务B修改的值得快照,此时事务A来查询这条数据的值,会发现这个trx_id=45,居然跟自己的ReadView 里的creator_trx_id(45)一样,说明这行数据就是自己修改的,自己修改的值是可以看到的。
接着事务A执行的过程中,突然开启了一个事务C,这个事务的id是78,然后它更新了那行数据的值为C,还提交了,这个时候A再去查询,会发现当前数据的trx_id=78,大于自己的ReadView中的max_trx_id(60)。
此时说明什么?
说明这个事务A开启之后,然后有一个事务更新了数据,自己是不能看到的,此时会顺着undo log多版本链条往下找,找到值A之前修改的那个值,因为那个trx_id=45跟自己的ReadView里的creator_trx_id是一样的,所以此时直接读取自己之前修改的那个版本。
(2)总结:
通过undo log多版本链条,加上开启事务时产生的一个ReadView,然后再有一个查询时,根据ReadView进行判断的机制,就知道应该读取哪个版本的数据了。
而且可以保证只能读到事务开启之前,别的提交事务更新的值,还有就是自己事务更新的值,假如事务更新之前,就有别的事务正在运行,然后开启事务之后别的事务更新的值,你是绝对读取不到的或者你事务开启之后,比你晚开启的事务更新的值,也是读取不到的。
知识点:
这个核心点就在于,不让当前事务看到这个事务开启后其他事务修改的数据,小于最小min_trx_id的绝对是执行完了的,因为这个mintrxid就是取得当前系统中还在执行的id集合,,
大于下一个生成trxid的数据绝对是后续出现的, 问题就是在这区间之间的trxid ,因为最小的可能是之前事务慢才没执行完的,在当前时刻,trxid在最大最小区间的也有可能已经执行完了,所以最后一道trxid集合,去看看这里面有没有,没有就是执行的快已经执行完了。
undo log 的Read View 机制类似于一个数据快照,将同一时间并发的修改某条数据的日志组成一个快照列表,当某个事务开启的Read View时,就会生成一个快照列表,列表记录了事务开启进行快照时 事务的id,包括最大和最小id,以及开启事务的id和活跃事务列表,根据这个快照列表的事务操作规则,可以有效的防止脏读,脏写,问题,比如 开启事务的id,只能看到比这个事务id小的以及本身修改的,看不到比它大的事务id,以及事务开启之后突然开启的其他的事务id