// session A
begin;
select * from t1 where id = 1 //
//session B
begin;
select * from t1 where id = 1
update t1 set amonut=amount+1 where id = 1
//session A
select * from t1 where id = 1 //v1
// session B
commit
// session A
select * from t1 where id = 1 //v2
commit
select * from t1 where id = 1 //v3
复制代码
上面的查询分析来分析每一个事务隔离级别下v1,v2,v3不一样的显示mysql
MySQL 中,实际上每条记录在更新的时候都会同时记录一条回滚操做。记录上的最新值,经过回滚操做,均可以获得前一个状态的值sql
假设一个值从1被按顺序的改成2,3,4,在回滚日志里面就会有下面的记录数据库
read-view A -> 将2改成1
read-view B -> 将3改成2 将4改成3
read-view C -> 当前值4
复制代码
经过不一样时刻启动不一样的read-view,在视图A,B,C里面,这个记录的值分别为1,2,4,同一记录存在多个版本,就是数据库的多版本(MVCC).对于 read-view A,要获得 1,就必须将当前值依次执行图中全部的回滚操做获得.同时你会发现,即便如今有另一个事务正在将 4 改为 5,这个事务跟 read-view A、B、C 对应的事务是不会冲突的session
在不须要的时候才删除。也就是说,系统会判断,当没有事务再须要用到这些回滚日志时,回滚日志会被删除,当系统里没有比这个回滚日志更早的 read-view 的时候就会删除.spa
长事务意味着系统里面会存在很老的事务视图。因为这些事务随时可能访问数据库里面的任何数据,因此这个事务提交以前,数据库里面它可能用到的回滚记录都必须保留,这就会致使大量占用存储空间.==长事务还占用锁资源,也可能拖垮整个库==日志
每一个事务都有一个事务ID,叫作transaction id(递增)code
事务在启动时,找到已提交的最大事务ID记为up_limit_id。事务
事务在更新一条语句时,好比id=1改成了id=2.会把id=1和该行以前的row trx_id写到undo log里,而且在数据页上把id的值改成2,而且把修改这条语句的transactionid记在该行行头资源
一个事务要查看一条数据时,必须先用该事务的up_limit_id与该行的transaction id作比对,若是up_limit_id>=transactionid,那么能够看.若是up_limit_id<transaction id,则只能去undo log里去取。去undo log查找数据的时候,也须要作比对,必须up_limit_id>transaction id,才返回数据it
// session A
start transaction with consistent snapshot //立刻启动事务
// session B
start transaction with consistent snapshot
// session C
UPDATE t set k=k+1 where id =1
// session B
UPDATE t set k=k+1 where id =1
SELECT k from t where id = 1 //查询结果 3
// session A
SELECT k from t where id = 1 //查询结果 1
commit
// session B
comit
复制代码
一个数据版本,对于一个事务视图来讲,除了本身的更新老是可见之外,有三种状况
上面的例子 咱们将事务C也进行声明事务,接下来看看会怎么样
// session A
start transaction with consistent snapshot //立刻启动事务
// session B
start transaction with consistent snapshot
// session C
start transaction with consistent snapshot // C也启动事务
UPDATE t set k=k+1 where id =1
// session B
UPDATE t set k=k+1 where id =1
SELECT k from t where id = 1 //查询结果 3
// session C
commit
// session A
SELECT k from t where id = 1 //查询结果 1
commit
// session B
comit
复制代码
相对于上个版原本说,事务B的更新的时候,事务C还未进行提交,这样的话当前A,B的查询结果会是什么样子呢?
上一篇文章中提到的“两阶段锁协议”就要上场了。事务 C’没提交,也就是说 (1,2) 这个版本上的写锁还没释放。而事务 B 是当前读,必需要读最新版本,并且必须加锁,所以就被锁住了,==必须等到事务 C’释放这个锁==,才能继续它的当前读
可重复读的核心就是==一致性读==;而事务更新数据的时候,只能用当前读。若是当前的记录的行锁被其余事务占用的话,就须要进入锁等待。而读提交的逻辑和可重复读的逻辑相似,它们最主要的区别是: