题图:pixabay
当前读和快照读。顾名思义,当前读就是读的是当前时刻已提交的数据,快照读就是读的是快照生成时候的数据。
这里概念理解要抛开读出跟写入的物理概念、读写分离的概念等等。这里的读包含了SELECT
、UPDATE
、INSERT
等语句中的处理逻辑。
# 快照是什么?
视图的逻辑概念。UNDO LOG + MVCC,后面单独讲。
当前时刻很好理解。执行语句的时刻,库里(磁盘+buffer)是什么样子就是什么样子。
快照的生成时间根据隔离级别的不同而有所不同。先复习下隔离级别:
- 读未提交。一个事务还没提交时,它做的变更就能被别的事务看到。
- 读提交。一个事务提交之后,它做的变更会被其他事务看到
- 可重复读。一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。未提交的数据对其他事务不可见
- 串行化。对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行
在读未提交隔离级别下,快照是什么时候生成的?
没有快照,因为不需要,怎么读都读到最新的。不管是否提交
在读已提交隔离级别下,快照是什么时候生成的?
SQL语句开始执行的时候。
在可重复读隔离级别下,快照是什么时候生成的?
事务开始的时候
# 下面来举个例子来理解下
1.读未提交
create table t(a int) engine=InnoDB;
# TODO:设置隔离级别
insert into t(a) values(1);
# 设置隔离级别-读未提交
set session transaction isolation level READ UNCOMMITTED;
1
2
3
4
5
2
3
4
5
事务A | 事务A结果 | 事务B | 事务B结果 | 解答 |
---|---|---|---|---|
begin transaction | begin transaction | 没有视图的概念 | ||
select a from t | 1 | |||
select a from t | 1 | |||
update t set a = 2 | ||||
select a from t | 2 | session A 能 读到 session B还未提交的数据 | ||
commit transaction | ||||
select a from t | 2 | |||
commit transaction | ||||
select a from t | 2 |
实操记录
2.读已提交
create table t(a int) engine=InnoDB;
# TODO:设置隔离级别
insert into t(a) values(1);
# 设置隔离级别-读已提交
set session transaction isolation level READ COMMITTED;
1
2
3
4
5
2
3
4
5
事务A | 事务A结果 | 事务B | 事务B结果 | 解答 |
---|---|---|---|---|
begin transaction | begin transaction | |||
select a from t | 1 | |||
select a from t | 1 | |||
update t set a = 2 | ||||
select a from t | 1 | |||
commit transaction | UNDO LOG data = 2 | |||
select a from t | 2 | |||
commit transaction | ||||
select a from t | 2 |
实操记录
3.可重复读
create table t(a int) engine=InnoDB;
# TODO:设置隔离级别
insert into t(a) values(1);
# 默认隔离级别
1
2
3
4
2
3
4
事务A | 事务A结果 | 事务B | 事务B结果 |
---|---|---|---|
begin transaction | begin transaction | ||
select a from t | 1 | ||
select a from t | 1 | ||
update t set a = 2 | |||
select a from t | 1 | ||
commit transaction | |||
select a from t | 1 | ||
commit transaction | |||
select a from t | 2 |
实操记录
# 怎么知道执行的语句是当前读还是快照读?
1.在默认隔离级别下,select 语句默认是快照读
select a from t where id = 1
1
2.select 语句加锁是当前读
# 共享锁
select a from t where id = 1 lock in share mode;
#排他锁
select a from t where id = 1 for update;
1
2
3
4
5
2
3
4
5
3.update 语句是当前读
update t set a = a + 1;
1