mysql table t
id(primary_k) | k |
1 | 1 |
事务A,B,C的执行流程 (RR隔离级别下)
事务A | 事务B | 事务C |
start transaction with consistent snapshot; | ||
start transaction with consistent snapshot; | ||
update t set k=k+1 where id=1; | ||
update t set k=k+1 where id=1; select k from t where id=1; | ||
select k from t where id=1; commit; | ||
commit; |
start transaction with consistent snapshot;命令可以立即启动一个事务;否则 begin/start transaction命令并不是事务的起点,而是执行到他们之后的第一个操作innodb表的语句,事务才会真正启动。
上述表格中,事务C没有显示的使用begin/commit,说明 update本身就是一个事务,语句执行完后自动提交;
上述事务执行结果,B查询到的k是3,而事务A查到的k是1
原因:
一个数据版本,对于一个事务视图来说,除了自己的更新总是可见之后,有以下3种情况:
1.版本未提交,不可见;
2.版本已提交,但是是在视图创建后提交的,不可见;
3.版本已提交,但是是在视图创建前提交的,可见。
基于以上,分析事务A的查询结果:
事务A的查询语句的视图数组在事务A启动的时候生成的,此时:
(1,3)还没提交(事务B执行结果),属于情况1
(1,2)虽然提交了(事务C执行结果),但是是在视图数组创建之后提交的,属于情况2,不可见。
(1,1)是在视图数组创建之前提交的,可见。
再来看事务B,根据一致性读,(1.2)是在事务B的视图创建之后提交的,应该不可见,可为啥B能读出来呢?
原因就在于select之前的update语句。 事务根据数据的时候,只能用当前读。如果没有update,那读出来的数据就是(1.1)而不是(1,2)了。
综上:可重复度的核心就是一致性读。而事务根据数据的时候,只能用当前读。如果当前的记录的行锁被其他事务占用(即事务未提交),就需要进入锁等待。
好,以上是可重复读隔离级别下的执行结果。