探究InnoDB可重复读

2017-10-18  本文已影响0人  他山之石头

在RC(Read Committed)和RR(Repeatable Read)两种事务隔离级别下,InnoDB存在两种数据读取方式:

快照读(Snapshot Read)

故名思意,快照读读取的都是快照数据,快照怎么来,在InnoDB引擎下是基于undo log,那undo log又是什么?举例说明,假设有这样一个表:

-- 表结构
CREATE TABLE `innodb_test` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(100) NOT NULL DEFAULT '0',
    `age` INT(11) NOT NULL DEFAULT '0',
    PRIMARY KEY (`id`),
    INDEX `idx_age` (`age`)
)
ENGINE=InnoDB;

-- 初始数据
INSERT INTO `innodb_test` (`id`, `name`, `age`) VALUES (1, '貂蝉', 100),(2, '庄周', 120),(3, '项羽', 130);

undo log的存在解决了两个问题,一是数据回滚,二是实现了MVCC (Multi-Version Concurrency Control) ,快照读读取的就是undo log中的数据,所以这种读取是不需要加锁的,避免了读写冲突。常见的快照读语句就是最常见的SELECT,比如:

SELECT * FROM innodb_test WHERE id=1;

快照读在RC和RR隔离级别下的表现却是不一样的,为了方便说明,现在将数据还原到初始数据,然后按照下表的顺序操作。

# 事务1 事务2
1 begin; begin;
2 SELECT * FROM innodb_test WHERE id=1;// 输出1-貂蝉-100
3 UPDATE innodb_test SET name='嬴政', age=90 WHERE id=1;
4 commit;
5 SELECT * FROM innodb_test WHERE id=1;// 输出???

当前读(Current Read)

而当前读,读取的是最新已提交数据,并且都会加行锁,如下语句都会产生当前读:

SELECT balabala LOCK IN SHARE MODE;
SELECT balabala FOR UPDATE;
INSERT balabala;
UPDATE balabala;
DELETE balabala;

当前读需要保证其他并发事务不能修改当前记录,对读取记录加锁。其中,第一条语句,对读取记录加S锁(共享锁),其他的操作,都加的是X锁(排它锁)。当前读在RC和RR隔离级别下的表现也是不一样的,为了方便说明,现在将数据还原到初始数据,然后按照下表的顺序操作。

# 事务1 事务2
1 begin; begin;
2 SELECT * FROM innodb_test WHERE age=120 FOR UPDATE;
3 insert into innodb_test(name, age) values('嬴政', 120);// 此时会发生什么?

总结

RR隔离级别下,快照读通过undo log来保证可重复读,当前读通过X(S)锁+GAP锁来保证可重复读,但显然快照读和当前读之间无法保证可重复读。本文对可重复读的实现机制做了阐述,关于undo log、锁等知识仅仅从简描述,后面有时间再详细写一下。


版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者高爽和本文原始地址:http://www.jianshu.com/p/17967b72139a

上一篇 下一篇

猜你喜欢

热点阅读