MySQL의 관련 (F) - 구현의 트랜잭션 격리 수준 (MVCC)

머리말

이전 기사 우리는 네 가지 속성 ACID 및 InnoDB의 트랜잭션 격리 수준의 MySQL의 업무를 소개 RU는, RC는 RR은, 직렬화, 내가 관련 아이를 판매 시간의 끝에서 우리가 InnoDB의 거래에 대해 생각해 봅시다 MySQL의에서 격리 수준은 달성하기 위해 당신이 너무 Zeyang, 어쨌든, 우리는 트랜잭션 격리 수준의 구현 오늘에 대한 이야기를 계속하려면 여기를 생각하면 알 수없는 방법이다.

티켓에 먼저 이전 규칙 :

  1. MySQL의 관련 (a)는 - 쿼리 어떻게 실행
  2. MySQL의 관련 (두) - 업데이트 문을 구현하는 방법입니다
  3. 관련 MySQL을 (사이드 스토리) - 이노 논리적 스토리지 구성 ;
  4. 관련 MySQL의 (C) - 인덱스 데이터 모델과 B + 트리 세부 공제 ;
  5. MySQL의 관련 (4 개) - 성능 최적화 키 인덱스
  6. MySQL의 관련 (E) - 특징 및 트랜잭션 격리 수준의 세부 사항

앞서 언급 한 바와 같이 마인드 맵, 우리는 [6] Xixuan는 다음에서 내 공개 마이크로 채널 번호를 얻기 위해 갈 수있는 완벽한 고화질 사진 회신 MySQL의 마음지도에 원하는 :
그림 삽입 설명 여기

본문

산책의 몸

우리는 먼저 시간 일관성의 문제를 해결하려면, 내가 할 방법, 일관성있는 결과 데이터에 두 번 트랜잭션 달성하기 위해 트랜잭션 격리를 읽을 수 있도록 대한 생각? 우리가 할 수있는 몇 가지 방법은 무엇입니까? 그것은 당신의 생각은 무엇인가?

전반적으로, 우리는이 두 가지 유형 의 프로그램을.

자랑하는 LBCC

첫 번째, 우리는 내가 두 번 같은 데이터를 읽기 전에 내가 조작 할 수있는 데이터를 잠글 때, 그때는 데이터를 읽을 수 있도록이 같은 다른 트랜잭션이 행에 수정하는 것을 허용하지 않습니다. 이 프로그램은 우리가 제어 잠금 기반 동시성 제어 (자랑하는 LBCC) 잠금 기반 동시성 호출합니다.

전용 잠금 기반 트랜잭션 격리를 달성하는 경우 트랜잭션이 다른 시간을 수정할 수 없습니다 읽을 때, 그 수단은 동시 읽기 및 쓰기 작업을 지원하지 않으며, 우리의 응용 프로그램의 대부분은 읽고 이하,이 의지를 작성하는 크게 운영 데이터의 효율성에 영향을 미친다.

MVCC

所以我们还有另一种解决方案,如果要让一个事务前后两次读取的数据保持一致,那么我们可以在修改数据的时候给它建立一个备份或者叫快照,后面再来读取这个快照就行了。这种方案我们叫做多版本的并发控制 Multi Version Concurrency Control (MVCC)。

MVCC 的核心思想是: 我可以查到在我这个事务开始之前已经存在的数据,即使它在后面被修改或者删除了。在我这个事务之后新增的数据,我是查不到的。

  • 问题:这个快照什么时候创建?读取数据的时候,怎么保证能读取到这个快照而不是最新的数据?这个怎么实现呢?

InnoDB 为每行记录都实现了两个隐藏字段:

DB_TRX_ID,6 字节:插入或更新行的最后一个事务的事务 ID,事务编号是自动递增的(我们把它理解为创建版本号,在数据新增或者修改为新数据的时候,记录当前事务 ID)。

DB_ROLL_PTR,7 字节:回滚指针(我们把它理解为删除版本号,数据被删除或记录为旧数据的时候,记录当前事务 ID)。

我们把这两个事务 ID 理解为版本号。
그림 삽입 설명 여기

第一个事务,初始化数据(检查初始数据)

//Transaction 1

begin;

insert into mvcctest values(NULL,'Jerry') ;

insert into mvcctest values(NULL,'jack') ;

commit;

此时的数据,创建版本是当前事务 ID,删除版本为空:

id name 创建版本 删除版本
1 Jerry 1 undefined
2 jack 1 undefined

第二个事务,执行第 1 次查询,读取到两条原始数据,这个时候事务 ID 是 2:

// Transaction 2
begin;
select * from mvcctest ;	-- (1) 第一次查询

第三个事务,插入数据:

// Transaction 3
begin;
insert into mvcctest values(NULL,'tom') ;
commit;

此时的数据,多了一条 tom,它的创建版本号是当前事务编号,3:

id name 创建版本 删除版本
1 Jerry 1 undefined
2 jack 1 undefined
3 tom 3 undefined

第二个事务,执行第 2 次查询:

Transaction 2
select * from mvcctest ;	(2) 第二次查询

MVCC 的查找规则:只能查找创建时间小于等于当前事务 ID 的数据,和删除时间大于当前事务 ID 的行(或未删除)。

也就是不能查到在我的事务开始之后插入的数据,tom 的创建 ID 大于 2,所以还是只能查到两条数据。

第四个事务,删除数据,删除了 id=2 jack 这条记录:

Transaction 4
begin;
delete from mvcctest where id=2;
commit;

此时的数据,jack 的删除版本被记录为当前事务 ID,4,其他数据不变:

id name 创建版本 删除版本
1 Jerry 1 undefined
2 jack 1 4
3 tom 3 undefined

在第二个事务中,执行第 3 次查询:

Transaction 2
select * from mvcctest ;	(3) 第三次查询

查找规则:只能查找创建时间小于等于当前事务 ID 的数据,和删除时间大于当前事务 ID 的行(或未删除)。

也就是,在我事务开始之后删除的数据,所以 jack 依然可以查出来。所以还是这两条数据。

第五个事务,执行更新操作,这个事务事务 ID 是 5:

Transaction 4
begin;
update mvcctest set name ='Mic' where id=1;
commit;

此时的数据,更新数据的时候,旧数据的删除版本被记录为当前事务 ID 5(undo),产生了一条新数据,创建 ID 为当前事务 ID 5:

id name 创建版本 删除版本
1 Jerry 1 5
2 jack 1 4
3 tom 3 undefined
1 Mic 5 undefined

第二个事务,执行第 4 次查询:

// Transaction 2
select * from mvcctest ;	(4) 第四次查询

查找规则:只能查找创建时间小于等于当前事务 ID 的数据,和删除时间大于当前事务 ID 的行(或未删除)。

因为更新后的数据 Mic 创建版本大于 2,代表是在事务之后增加的,查不出来。

而旧数据 Jerry 的删除版本大于 2,代表是在事务之后删除的,可以查出来。

通过以上演示我们能看到,通过版本号的控制,无论其他事务是插入、修改、删除,第一个事务查询到的数据都没有变化。

在 InnoDB 中,MVCC 是通过 Undo log 实现的。

Oracle、Postgres 等等其他数据库都有 MVCC 的实现。

需要注意,在 InnoDB 中,MVCC 和锁是协同使用的,这两种方案并不是互斥的。第一大类解决方案是锁,锁又是怎么实现读一致性的呢?

关于锁的知识已经在快马加鞭准备了,且听下回分解~

By the way

有问题?可以给我留言或私聊
有收获?那就顺手点个赞呗~

当然,也可以到我的公众号下「6曦轩」,

回复“学习”,即可领取一份
【Java工程师进阶架构师的视频教程】~

回复“面试”,可以获得:
【本人呕心沥血整理的 Java 面试题】

回复“MySQL脑图”,可以获得
【MySQL 知识点梳理高清脑图】

때문에 내 담요, 숙련 된 프로그래머의 PHP, 안드로이드와 하드웨어 짓을했지만 결국 자바 일에 집중하기로 결정했습니다, 그래서 문제가 (감정적 인 대화 기술이 하, 하, 하 수 있음)를 참조하십시오 공개 토론 질문의 수가있을 수 있습니다 무엇 단어가 서버 아키텍처에, 당신과 함께 학습 진행을 기대 가능한 한 빨리 회신 해 드리겠습니다, 자바 코어 분석 지식, 경력, 인터뷰 요약 및 다른 기사 가끔 출력, 환영 관심을 밀어 준수 ~ ~ ~

그림 삽입 설명 여기

게시 34 개 원래 기사 · 원 찬양 9 ·은 10000 +를 볼

추천

출처blog.csdn.net/weixin_42669785/article/details/104209243