2021-04-02 举例说明RC和RR下READVIEW不同

2021-04-02  本文已影响0人  5A风景区

生成测试表ttt,插入一条数据

CREATE TABLE `ttt` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL DEFAULT '' COMMENT '',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

insert into ttt (name) values ('TOM');

RC隔离级别下

READ COMMITED在每一次查询的时候都会生成一个新的Read View

事务A trx_id = 100

begin;
UPDATE ttt SET name='JORY' WHERE ID = 1;
UPDATE ttt SET name='WUJIU' WHERE ID = 1;

注: trx_id = 100 是假设的,可以通过一下语句查看实际trx_id

SELECT tx.trx_id FROM information_schema.innodb_trx tx ;

事务B trx_id = 200

BEGIN;
第一步.在提交了事务A之前:做一些其他操作,但是并没有更改table

第二步.在提交了事务A之后:
UPDATE ttt SET name='Mag' WHERE ID = 1;
UPDATE ttt SET name='Cool' WHERE ID = 1;

事务C trx_id = 300

SELECT * FROM ttt WHERE id = 1;
//执行一些其他操作 . . .并且此时事务A已经提交了
doSomething; 
//再次查询,数据会与第一次查询不一致
SELECT * FROM ttt WHERE id = 1;
不一致

结论:在READ COMMITED隔离界别下,每次查询都会创建一个新的Read View,每次都是读取最新版本的Read View合适的数据行,因此当在事务中出现其他事务对某一数据行操作,得到的两次结果可能不一致。

RR隔离级别下

在REPEATABLE READ级别下,每个事务只生成一个Read View,该快照作用于整个事务的生命过程

事务A trx_id = 100

begin;
UPDATE ttt SET name='JORY' WHERE ID = 1;
UPDATE ttt SET name='WUJIU' WHERE ID = 1;

注: trx_id = 100 是假设的,可以通过一下语句查看实际trx_id

SELECT tx.trx_id FROM information_schema.innodb_trx tx ;

事务B trx_id = 200

BEGIN;
第一步.在提交了事务A之前:做一些其他操作,但是并没有更改table

第二步.在提交了事务A之后:
UPDATE ttt SET name='Mag' WHERE ID = 1;
UPDATE ttt SET name='Cool' WHERE ID = 1;

事务C trx_id = 300

SELECT * FROM ttt WHERE id = 1;
//执行一些其他操作 . . .并且此时事务A已经提交了
doSomething; 
//再次查询,数据会与第一次查询不一致
SELECT * FROM ttt WHERE id = 1;
一致
结论:REPEATABLE READ在整个事务周期内,总是使用同一个快照,因此整个事务期间,所能够查找到的数据永远是一致的。

由此,MVCC解决了 不可重复读 的问题,
然而,幻读问题MVCC依然无法解决

解决幻读依靠一下两种方法:

1.使用串行化的隔离界别,所有事务串行运行,完全避免

2.使用Next-Key Lock策略

毫无疑问,在不到万不得已的情况下,我们是不会选择第一种方案的,原因很简单,效率太糟糕.
;如何使用Next-Key Lock策略,解决幻读问题,我们在下一章讲解...

上一篇下一篇

猜你喜欢

热点阅读