简单介绍
哪些事务隔离级别会产生read View视图?
可重复读和读已提交。
这里我们要理解mvcc是干啥的?它是解决并发事务下的隔离性问题的。读未提交的级别总是能读取到所有事务的最新操作结果,没有隔离性的概念;而串行化则要求事务必须单条依次执行,也就没有了并发的场景。这两种场景下都不需要mvvc机制;
可重复读和读已提交分别在什么时候生成read view视图?
可重复读在事务开始时执行,第一次读取数据时生成;读已提交则是在每次读取的时候都生成一遍。
原因是可重复读需要保证一个事务在整个发生的过程中,看到的快照读都是一致的,不会发生变化,所以read view也就只需要最开始的时候生成一次;但是读已提交在每次查询的时候都要去看一下其他的事务的提交情况,所以需要每次查询的时候都生成一遍。
怎么才能算一个事务是开始了呢?
当第一个涉及到修改操作(insert、update、delete)的时候,MySQL才会分配一个事务id.
为什么只有写操作的时候才会分配事务id呢?
如果任何一种事务开始都被立刻分配事务id,尤其是对于事务中只产生了查询语句的情况下,并没有产生任何数据的修改,则会造成多余的性能浪费。
性能的浪费主要体现在1、事务id分配时的锁竞争,2、事务id生成后要进行的日志记录(undolog、redolog),3、简化事务管理,仅查询的事务可以避免基于事务id的视图数组判断,获取数据直接通过read view来进行即可。
如果一个事务先执行的查询语句,而不是写语句,也就是说现在事务还没有被分配事务id,它查询的read view是依据什么来进行的呢?
不同的事务隔离级别将有不同的处理:
隔离级别和Read-View的处理
-
读已提交(Read Committed):
- 在这个隔离级别下,事务每次执行查询时都会生成一个新的一致性视图。由于事务尚未分配事务ID,一致性视图将包含所有在查询时刻尚未提交的事务(即那时的活动事务)。
-
可重复读(Repeatable Read):
- 在这个隔离级别下,事务在第一次查询时生成一致性视图,然后在事务结束之前保持这个视图不变。如果事务开始时还没有事务ID,视图将基于当前数据库中的所有活动事务生成。即使该事务后来执行了写操作并被分配了事务ID,它仍然使用最初创建时的一致性视图。
一致性视图的内容
- 一致性视图主要包含了在视图创建时刻所有“活跃”的事务ID。这些事务ID代表了那些已经开始但尚未提交的事务。
查询处理
- 当事务执行查询操作时,它会根据一致性视图来确定哪些数据版本是可见的。如果事务还没有被分配事务ID,它视为一个只读事务,直到它执行第一个写操作。
min_id <=trx_id<= max_id,但是row 的 trx_id 不在视图数组中,这是怎么产生的?不是互相矛盾的吗?
这里其实是一个事务id分配的顺序性和事务执行完成的非顺序性导致的时间差问题。
首先,事务id在分配的时候是单调递增的(1、2、3、4、5),但是事务在完成提交的时候并不一定是顺序的(1、2、4、3、5)。
在视图数组生成的时候其本质目的是将事务分成两类【未提交事务】【已提交事务】,但是在判断的时候在逻辑上进行了两层判断【与min_id和max_id的关系】【是否在视图数组中】。
1.在判断一个事务是否提交的时候,如果trx_id<min_id,则肯定是已提交的。这相当于一种逻辑剪枝,因为大部分的已提交事务通过这一步判断就够了。
2.如果min_id <=trx_id<= max_id,但是row 的 trx_id 不在视图数组中。说明在【事务2】开始创建视图的时候,【事务4】仍然是活跃的,但是在视图创建完成的时候,【事务4】已经提交了。而这种情况下也是【已提交事务】,对事务2来讲,事务4的结果也是可见的。