insert undo只在事务回滚时起作用,当事务提交后,该类型的undo日志就没用了,它占用的Undo LogSegment也会被系统回收(也就是该undo日志占用的Undo页面链表要么被重用,要么被释放)。假设之后两个事务id分别为10、20的事务对这条记录进行UPDATE操作,操作流程如下:
能不能在两个事务中交叉更新同一条记录呢?不能!这不就是一个事务修改了另一个未提交事务修改过的数据,脏写。每次对记录进行改动,都会记录一条undo日志,每条undo日志也都有一个roll_pointer属性(INSERT操作对应的undo日志没有该属性,因为该记录并没有更早的版本),可以将这些undo日志都连起来,串成一个链表:
InnoDB使用锁来包管不会有脏写情况的发生,也就是在第一个事务更新了某条记录后,就会给这条记录加锁,另一个事务再次更新时就必要等待第一个事务提交了,把锁释放之后才可以继续更新。
说明:只有在对表中的数据做改动时(执行INSERT、UPDATE、DELETE这写语句时)才会为事务分配事务id,否则在一个只读事务中的事务id值默认为0。2.trx_ids,表示在天生ReadView时当前系统中活泼的读写事务的事务id列表。
注意: low_limit_id并不是trx_ids中的最大值,事务id是递增分配的。比如,现在有id为1,2,3这三个事务,之后id为3的事务提交了。那么一个新的读事务在天生ReadView时,trx_ids就包罗1和2,up_limit_id的值就是1,low_limit_id的值就是4。举例:
InnoDB中,MVCC是通过Undo Log + Read View进行数据读取,Undo Log保存了汗青快照,而Read View规则帮我们判断当前版本的数据是否可见。在隔离级别为读未提及(Read Committed)时,一个事务中的每一次SELECT查询都会重新获取一次Read View。
注意,此时同样的查询语句都会重新获取一次 Read View,这时如果 Read View 不同,就可能产生不可重复读或者幻读的情况。当隔离级别为可重复读的时候,就避免了不可重复读,这是因为一个事务只在第一次 SELECT 的时候会获取一次 Read View,而后面所有的 SELECT 都会复用这个 Read View,如下表所示:
说明:事务执行过程中,只有在第一次真正修改记录时(比如使用INSERT、DELETE、UPDATE语句),才会被分配一个单独的事务id,这个事务id是递增的。所以我们才在事务20中更新一些别的表的记录,目标是让它分配事务id。此时,表student中id为1的记录得到的版本链表如下所示:
强调:使用READ COMMITTED隔离级别的事务在每次查询开始时都会天生一个独立的ReadView,5.2 REPEATABLE READ隔离级别的事务
说明:我们之前说执行DELETE语句或者更新主键的UPDATE语句并不会立即把对应的记录完全从页面中删除,而是执行一个所谓的delete mark操作,相当于只是对记录打上了一个删除标志位,这重要就是为MVCC服务的。通过MVCC 我们可以解决:
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) | Powered by Discuz! X3.4 |