1.2MySQL-InnoDB-READ COMMITTED(读已提交)

1.设置为读已提交

SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

2.此时TA执行插入,并查询,可以查询到结果

1.2MySQL-InnoDB-READ COMMITTED(读已提交)_第1张图片

3.TB不能查到结果

1.2MySQL-InnoDB-READ COMMITTED(读已提交)_第2张图片

证明已经不能读到未提交的数据

但是仍然存在不可重复读问题 (同一事务内两次读的数据不一致)

4.为了演示效果,把用户数据插入数据库并提交,此时表中有一条id为1的 name为aaa的记录

TB开启一个事务 并进行查询

1.2MySQL-InnoDB-READ COMMITTED(读已提交)_第3张图片

5.此时TA进行数据修改,并提交

1.2MySQL-InnoDB-READ COMMITTED(读已提交)_第4张图片

6.B再次查询可以看到A事务已经提交的结果

1.2MySQL-InnoDB-READ COMMITTED(读已提交)_第5张图片

根据测试可以发现,先开启的事务TA在事务TB提交之前进行的查询和TB提交之后进行的第二次查询,两次查询结果不一致,出现不可重复读情况。

如果要避免不可重复读,至少要把事务隔离级别设为:1.3 MySQL-InnoDB-REPEATABLE READ(可重复读)

InnoDB采用了MVCC(Multiversion Concurrency Control)多版本并发控制,避免不可重复读。MVCC只在 READ COMMITTED 和 REPEATABLE READ 2个隔离级别下工作。MVCC会建立多个ReadView,RC是语句级多版本(事务的多条只读语句,创建不同的ReadView,代价更高),RR是事务级多版本(一个事务有一个ReadView)。由于RC中未提交的事务,不允许其他事务看到,但是本身事务需要看到,所以执行多条语句时,都需要建立新的ReadView,以支持本事务后面的查询。

注:

MVCC本意应该是下面的样子:

每行数据都存在一个版本,每次数据更新时都更新该版本

修改时Copy出当前版本随意修改(类似于Java并发包中的CopyOnWrie操作),各个事务之间无干扰

保存时比较版本号,如果成功(commit),则覆盖原记录;失败则放弃copy(rollback)

但是InnoDB的实现有一些差别:

事务以排他锁的形式修改原始数据

把修改前的数据存放于Undo log,通过回滚指针与主数据关联

修改成功(commit)啥都不做,失败则恢复Undo log中的数据(rollback)

你可能感兴趣的:(MySQL)