生成测试表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策略,解决幻读问题,我们在下一章讲解...
网友评论