>  기사  >  데이터 베이스  >  MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

PHPz
PHPz앞으로
2023-06-03 11:51:02813검색

    1.MVCC

    MVCC(Multiversion Concurrency Control), 다중 버전 동시성 제어란 무엇인가요? 이름에서 알 수 있듯이 MVCC는 데이터 행의 다중 버전 관리를 통해 데이터베이스 동시성 제어를 구현합니다. 이 기술은 InnoDB의 트랜잭션 격리 수준에서 일관된 읽기 작업이 수행되도록 보장합니다. 즉, 다른 트랜잭션에 의해 업데이트되고 있는 일부 행을 쿼리하여 업데이트되기 전의 값을 확인할 수 있기 때문에 쿼리 수행 시 다른 트랜잭션이 잠금을 해제할 때까지 기다릴 필요가 없다. . MVCC (Multiversion Concurrency Control),多版本并发控制。顾名思义,MVCC是通过数据行的多个版本管理来实现数据库的并发控制。这项技术使得在InnoDB的事务隔离级别下执行一致性读.操作有了保证。换言之,就是为了查询一些正在被另一个事务更新的行,并且可以看到它们被更新之前的值,这样在做查询的时候就不用等待另一个事务释放锁。

    MVCC没有正式的标准,在不同的DBMS中MVCC的实现方式可能是不同的,也不是普遍使用的(大家可以参考相关的DBMS文档)。这里讲解InnoDB中 MVCC的实现机制(MySQL其它的存储引擎并不支持它)

    2快照读与当前读

    MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁非阻塞并发读,而这个读指的就是快照读,而非当前读。当前读实际上是一种加锁的操作,是悲观锁的实现。而MVCC本质是采用乐观锁思想的一种方式。

    2.1 快照读

    快照读又叫一致性读,读取的是快照数据。不加锁的简单的SELECT都属于快照读MVCC에는 공식적인 표준이 없습니다. MVCC의 구현은 DBMS마다 다를 수 있으며 보편적으로 사용되지 않습니다(관련 DBMS 문서를 참조할 수 있습니다). 여기에서는 InnoDB에서 MVCC의 구현 메커니즘을 설명합니다(다른 MySQL 스토리지 엔진은 이를 지원하지 않습니다)

    2 스냅샷 읽기 및 현재 읽기

    MySQL InnoDB에서 MVCC 구현은 주로 데이터베이스 동시성 성능을 향상하고 더 나은 방법을 사용하는 것입니다. 읽기-쓰기 충돌이 있는 경우에도 잠금 없음비차단 동시 읽기가 달성될 수 있도록 읽기-쓰기 충돌을 처리합니다. 이 읽기는 현재 읽기가 아닌 스냅샷 읽기를 나타냅니다. 현재 읽기는 실제로 잠금 작업이자 비관적 잠금 구현입니다. MVCC의 본질은 낙관적 잠금 사고를 사용하는 방식입니다.

    2.1 스냅샷 읽기

    스냅샷 읽기는 일관성 읽기라고도 하며, 스냅샷 데이터를 읽습니다. 잠금이 없는 간단한 SELECT는 모두 스냅샷 읽기입니다. 즉, 잠금 없이 비차단 읽기를 의미합니다.

    select * from player where ...

    스냅샷 읽기가 발생하는 이유는 동시성 성능을 향상시키기 위한 것입니다. MVCC를 기반으로 하며 많은 경우 잠금 작업을 피하고 오버헤드를 줄입니다. 여러 버전을 기반으로 하기 때문에 스냅샷 읽기는 반드시 최신 버전의 데이터를 읽을 필요는 없고, 이전 기록 버전일 수도 있습니다.

    스냅샷 읽기의 전제는 격리 수준이 직렬 수준이 아니라는 것입니다. 직렬 수준의 스냅샷 읽기는 현재 읽기로 변질됩니다. MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    2.2 현재 읽기

    현재 읽기는 최신 버전의 레코드(데이터의 과거 버전이 아닌 최신 데이터)를 읽습니다. 읽을 때 다른 동시 트랜잭션이 현재 레코드를 수정할 수 없도록 하는 것도 필요합니다. 읽은 기록이 잠금 처리됩니다. 잠긴 SELECT 또는 데이터 추가, 삭제 또는 수정으로 인해 현재 읽기가 발생합니다.

    예:

    3. 검토MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    3.1 격리 수준에 대해 다시 이야기해 보겠습니다.

    트랜잭션에는 4가지 격리 수준이 있으며 세 가지 동시성 문제가 있을 수 있습니다.

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    MysQL에서 , 기본값은 반복 읽기입니다. 이는 더티 읽기 및 반복 불가능 읽기 문제를 해결할 수 있습니다. 정의 관점에서만 팬텀 읽기 문제를 해결할 수는 없습니다. 팬텀 읽기 문제를 해결하려면 직렬화, 즉 격리 수준을 최고 수준으로 높여야 하지만 이렇게 하면 데이터베이스의 트랜잭션 동시성 기능이 크게 저하됩니다.

    MVCC는 잠금 메커니즘을 사용하는 대신 낙관적 잠금을 통해 반복 불가능 읽기 및 팬텀 읽기 문제를 해결할 수 있습니다. 대부분의 경우 행 수준 잠금을 대체하고 시스템 오버헤드를 줄일 수 있습니다.

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    3.2 숨겨진 필드, 실행 취소 로그 버전 체인

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석실행 취소 로그 버전 체인을 되돌아보면 InnoDB 스토리지 엔진을 사용하는 테이블의 클러스터형 인덱스 레코드에는 두 개의 필수 숨겨진 열이 포함되어 있습니다.

    trx_id: 트랜잭션이 클러스터형 인덱스 레코드를 변경할 때마다 트랜잭션의 트랜잭션 ID가 trx_id 숨겨진 열에 할당됩니다. Roll_pointer: 클러스터형 인덱스 레코드가 수정될 때마다 이전 버전이 Undo 로그에 기록됩니다. 그러면 이 숨겨진 열은 레코드 이전의 정보를 찾을 수 있는 포인터와 같습니다. MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    4. ReadView의 MVCC 구현 원리

    🎜🎜 MVCC 구현은 다음에 따라 달라집니다. 🎜숨겨진 필드, 실행 취소 로그, 읽기 보기🎜🎜4.1 ReadView란 무엇입니까🎜 🎜 MV에서 CC 메커니즘에서는 동일한 행 레코드를 업데이트하는 여러 트랜잭션이 여러 기록 스냅샷을 생성하고 이러한 기록 스냅샷은 실행 취소 로그에 저장됩니다. 트랜잭션이 이 행 레코드를 쿼리하려면 어떤 버전의 행 레코드를 읽어야 합니까? 이때 ReadView를 사용해야 하며 이는 행 가시성 문제를 해결하는 데 도움이 됩니다. 🎜

    트랜잭션이 MVCC 메커니즘을 사용하여 스냅샷 읽기 작업을 수행하면 ReadView라는 읽기 뷰가 생성됩니다. 트랜잭션이 시작되면 데이터베이스 시스템의 현재 스냅샷이 생성됩니다. InnoDB는 시스템에서 현재 활성 트랜잭션의 ID를 기록하고 유지하기 위해 각 트랜잭션에 대한 배열을 구성합니다("활성"이란 시작되었지만 아직 제출되지 않음을 의미함). ).

    4.2 디자인 아이디어

    READ UNCOMMITTED 격리 수준 트랜잭션을 사용하세요. 커밋되지 않은 트랜잭션으로 수정된 레코드를 읽을 수 있으므로 SERIALIZABLE 격리 수준 트랜잭션, InnoDB에서는 레코드에 액세스하려면 잠금이 필요합니다. READ UNCOMMITTED隔离级别的事务,由于可以读到未提交事务修改过的记录,所以直接读取记录的最新版本就好了。

    使用SERIALIZABLE隔离级别的事务,InnoDB规定使用加锁的方式来访问记录。

    使用READ COMMITTEDREPEATABLE READ隔离级别的事务,都必须保证读到已经提交了的事务修改过的记录。假如另一个事务已经修改了记录但是尚未提交,是不能直接读取最新版本的记录的,核心问题就是需要判断一下版本链中的哪个版本是当前事务可见的,这是ReadView要解决的主要问题。

    这个ReadView中主要包含4个比较重要的内容,分别如下:

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    4.3 ReadView的规则

    有了这个ReadView,这样在访问某条记录时,只需要按照下边的步骤判断记录的某个版本是否可见。

    • 如果被访问版本的trx_id属性值与ReadView中的creator_trx_id值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。

    • 如果被访问版本的trx_id属性值小于ReadView中的up_limit_id值,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以该版本可以被当前事务访问。

    • 如果被访问版本的trx_id属性值大于或等于ReadView中的low_limit_id值,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问。

    • 如果被访问版本的trx_id属性值在ReadView的up_limit_idlow_limit_id之间,那就需要判断一下trx_id属性值是不是在trx_ids列表中。如果在,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问。如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问。 4.4 MVCC整体操作流程

    了解了这些概念之后,我们来看下当查询一条记录的时候,系统如何通过MVCC找到它:

    • 1.首先获取事务自己的版本号,也就是事务ID;

    • 2.获取ReadView;

    • 3.查询得到的数据,然后与ReadView中的事务版本号进行比较;

    • 4.如果不符合Readview规则,就需要从Undo Log中获取历史快照;

    • 5.最后返回符合规则的数据。

    如果某个版本的数据对当前事务不可见的话,那就顺着版本链找到下一个版本的数据,继续按照上边的步骤判断可见性,依此类推,直到版本链中的最后一个版本。如果最近版本不可见,则该记录对该事务不可见,并且查询结果中不包含该记录。

    InnoDB中,MVCC是通过Undo Log + Read View进行数据读取,Undo Log保存了历史快照,而Read View规则帮我们判断当前版本的数据是否可见。

    在隔离级别为读已提交(Read Committed)时,一个事务中的每一次select查询都会重新获取一次Read View。

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    当隔离级别为可重读的时候,就避免了不可重复读,这是因为一个事务只在第一次select的时候会获取一次Read View,而后面所有的select都会复用这个Read View,

    如下所示:

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    5.举例说明

    假设现在student表中只有一条由事务id8事务插入一条记录:

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    MVCC只能在READ COMMITTED和REPEATABLE READ两个隔离级别下工作。接下来看一下READ COMMITTEDREPEATABLE READ所谓的生成Readview的时机不同到底不同在哪里。

    5.1 READ COMMITTED

    隔离级别下:

    READ COMMITTED:每次读取数据前都生成一个ReadView

    READ COMMITTEDREPEATABLE READ 격리 수준을 사용하세요. 트랜잭션은 레코드가 커밋된 트랜잭션을 읽습니다. 다른 트랜잭션이 레코드를 수정했지만 아직 제출하지 않은 경우 핵심 문제는 버전에서 어떤 버전인지 확인해야 합니다. 이것이 ReadView가 해결해야 할 주요 문제입니다. 🎜🎜이 ReadView에는 주로 다음과 같은 4가지 중요한 내용이 포함되어 있습니다.🎜🎜. /img.php.cn/upload/article/000/000/164/168576427063836.png" alt="MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석" />🎜🎜4.3 ReadView 규칙🎜 🎜이 ReadView를 사용하면 레코드의 특정 버전이 표시되는지 확인하려면 아래 단계만 수행하면 됩니다. 🎜
    • 🎜액세스된 버전이 표시되는 경우 trx_id 값. 속성은 ReadView의 creator_trx_id 값과 동일합니다. 이는 현재 트랜잭션이 자체 수정된 레코드에 액세스하고 있으므로 이 버전은 현재 트랜잭션에서 액세스할 수 있음을 의미합니다 🎜
    • 🎜 액세스한 버전의 trx_id 속성 값이 ReadView의 up_limit_id 값보다 작으면 현재 트랜잭션이 ReadView를 생성하기 전에 이 버전을 생성한 트랜잭션이 커밋되었음을 나타냅니다. 버전은 현재 트랜잭션 🎜
    • 에서 접근할 수 있습니다. >
    • 🎜 접근한 버전의 trx_id 속성 값이 ReadView의 low_limit_id 값보다 크거나 같다는 의미입니다. 이 버전을 생성한 트랜잭션은 현재 트랜잭션이 ReadView를 생성한 후에 시작되었으므로 이 버전은 현재 트랜잭션 액세스가 될 수 없습니다. 🎜
    • 🎜액세스된 버전의 trx_id 속성 값이 ReadView의 up_limit_id 사이에 있는 경우. low_limit_id인 경우 trx_id 속성 값이 trx_ids 목록에 있는지 여부를 결정해야 합니다. 그렇다면 이 버전을 생성한 트랜잭션이 ReadView가 생성될 때 여전히 활성 상태였으며 이 버전에 액세스할 수 없음을 의미합니다. 그렇지 않은 경우 ReadView가 생성될 때 이 버전을 생성한 트랜잭션이 커밋되었으며 이 버전에 액세스할 수 있음을 의미합니다. 4.4 전반적인 MVCC 작업 프로세스 🎜
    🎜이러한 개념을 이해한 후 레코드를 쿼리할 때 시스템이 MVCC를 통해 어떻게 찾는지 살펴보겠습니다. 🎜
    • 🎜1. 먼저 트랜잭션 자체의 버전 번호, 즉 트랜잭션 ID를 가져옵니다.🎜
    • 🎜2. ReadView 받기;🎜
    • 🎜3. 획득한 데이터를 쿼리한 후 ReadView의 트랜잭션 버전 번호와 비교하세요.🎜
    • 🎜4. Readview 규칙을 충족하지 않으면 실행 취소 로그에서 기록 스냅샷을 얻어야 합니다.🎜
    • 🎜5. 마지막으로 규칙을 준수하는 데이터가 반환됩니다. 🎜
    🎜특정 버전의 데이터가 현재 트랜잭션에 표시되지 않는 경우 버전 체인을 따라 다음 버전의 데이터를 찾고 위 단계를 계속 수행하여 가시성을 결정합니다. on, 버전 체인의 마지막 버전까지. 최신 버전이 표시되지 않는 경우 해당 레코드는 트랜잭션에 표시되지 않으며 쿼리 결과에도 포함되지 않습니다. 🎜🎜InnoDB에서 MVCC는 Undo Log + Read View를 통해 데이터를 읽습니다. Undo Log는 기록 스냅샷을 저장하고 Read View 규칙은 현재 버전의 데이터가 표시되는지 확인하는 데 도움이 됩니다. 🎜🎜격리 수준이 읽기 커밋됨이면 트랜잭션의 각 선택 쿼리가 읽기 보기를 다시 얻습니다. 🎜🎜MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석🎜🎜 격리 수준 다시 읽을 수 있으면 반복 불가능한 읽기가 방지됩니다. 이는 트랜잭션이 첫 번째 선택 중에 읽기 보기를 한 번만 얻고 이후의 모든 선택에서는 이 읽기 보기를 재사용하기 때문입니다. 🎜🎜다음과 같습니다. 🎜🎜MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석 🎜

    5. 예

    🎜트랜잭션 ID8인 트랜잭션에 의해 학생 테이블에 단 하나의 레코드가 삽입되었다고 가정합니다. 🎜🎜MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석🎜 🎜MVCC는 READ COMMITTED 및 REPEATABLE READ의 두 가지 격리 수준에서만 작동할 수 있습니다. 다음으로 READ COMMITTEDREPEATABLE READ의 Readview 생성 타이밍의 차이를 살펴보겠습니다. 🎜🎜5.1 READ COMMITTED🎜🎜격리 수준에서: 🎜🎜READ COMMITTED: 각 데이터 읽기 전에 ReadView 생성🎜

    이제 트랜잭션 ID 10과 20이 실행되는 두 개의 트랜잭션이 있습니다.

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    참고: 트랜잭션 실행 중에는 레코드가 실제로 처음으로 수정될 때만(예: INSERT, DELETE, UPDATE 사용) 명세서) 별도의 거래 ID가 할당되며, 이 거래 ID가 증가합니다. 이것이 바로 트랜잭션 ID를 할당할 수 있도록 트랜잭션 2의 다른 테이블에 있는 일부 레코드를 업데이트한 이유입니다.

    이 순간, 학생 테이블의 ID가 1인 레코드가 얻은 버전 연결 목록은 다음과 같습니다.

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    READ COMMITED 격리 수준을 사용하는 트랜잭션이 실행되기 시작한다고 가정합니다.

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    이 SELECT1의 실행 과정은 다음과 같습니다.

    1단계∶SELECT 문을 실행하면 ReadView의 trx_ids 내용이 먼저 생성됩니다. 목록은 [10, 20 ], up_limit_id10, low_limit_id21, >creator_trx_id 0입니다. ReadView ,ReadView的trx_ids列表的内容就是[10,20],up_limit_id10, low_limit_id21 , creator_trx_id0
    步骤2:从版本链中挑选可见的记录,从图中看出,最新版本的列name的内容是'王五',该版本的trx_id值为10,在trx_ids列表内,所以不符合可见性要求,根据roll_pointer跳到下一个版本。
    步骤3:下一个版本的列name的内容是'李四',该版本的trx_id值也为10,也在trx_ids列表内,所以也不符合要求,继续跳到下一个版本。
    步骤4:下一个版本的列 name的内容是‘张三',该版本的trx_id值为8,小于ReadView 中的up_limit_id值10,所以这个版本是符合要求的,最后返回给用户的版本就是这条列name为‘张三’的记录。

    之后,我们把事务id10的事务提交一下:

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    然后再到事务id20的事务中更新一下表studentid12단계: 버전 체인에서 보이는 레코드를 선택합니다. 그림에서 볼 수 있듯이 최신 버전의 name 열 내용은 '王五'입니다. trx_id 값의 버전은 trx_ids 목록에 있는 10이므로 가시성 요구 사항을 충족하지 못하고 Roll_pointer에 따라 다음 버전으로 점프합니다.

    3단계: 다음 버전의 name 열 내용은 'lee思'이고, 이 버전의 trx_id 값은 또한 10 trx_ids 목록에 있으므로 요구 사항을 충족하지 않고 계속해서 다음 버전으로 이동합니다.

    4단계: 다음 버전의 name 열 내용은 ‘Zhang San'이고, 이 버전의 trx_id 값은 다음과 같습니다. 8 는 ReadView의 up_limit_id 값 10보다 작으므로 이 버전이 요구 사항을 충족합니다. 최종적으로 사용자에게 반환되는 버전은 열 이름이 "Zhang San"인 레코드입니다. MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    그 후 id 거래가 10인 거래를 제출합니다.

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    그런 다음 트랜잭션 ID20인 트랜잭션으로 이동합니다. code> <code>student 테이블에서 id가 있는 레코드를 1로 업데이트합니다.

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    현재 레코드 버전은 테이블에 ID 1이 있는 Student 체인은 다음과 같습니다.

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    그런 다음 방금 READ COMMITTED 격리 수준 을 사용한 트랜잭션에서 ID가 1인 레코드를 다음과 같이 계속 검색합니다.


    이 SELECT2의 실행 과정은 다음과 같습니다.

    1단계∶
    SELECT 문을 실행하면 ReadView의 trx_ids 목록 내용이 [20], up_limit_id가 20, low_limit_id는 21이고 creator_trx_id는 0입니다.

    2단계:

    버전 체인에서 보이는 레코드를 선택하세요. 그림에서 볼 수 있듯이 최신 버전의 열 이름 내용은 "Song Ba"이고, 이 버전의 tr_id 값은 20입니다. trx_ids 목록에 있으므로 가시성 요구 사항을 충족하지 못하고 Roll.pointer에 따라 다음 버전으로 이동합니다.

    3단계∶다음 버전의 열 이름 내용은 "Qian Qi"입니다. 이번 버전의 trx_id 값은 20인데, 이 값도 trx_ids 목록에 있어서 요구 사항을 충족하지 못하고 계속해서 점프하고 있습니다. 다음 버전으로.

    4단계: 다음 버전의 열 이름 내용은 "王五"입니다. 이 버전의 trx_id 값은 10으로 ReadView의 up_limit.id 값 20보다 작으므로 이 버전은 요구 사항을 충족하며 최종적으로 사용자에게 반환된 버전은 열 이름이 "王五"인 레코드입니다.

    유추하자면, 트랜잭션 ID 20의 레코드도 나중에 제출된 경우, 테이블 Student의 ID 값 1인 레코드가 READ CONMMITTED 격리 수준을 사용하는 트랜잭션에서 다시 쿼리되면 결과는 "Song Ba"가 됩니다. 특정 프로세스를 분석합니다.

    5.2 REPEATABLE READ

    격리 수준에서:

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    REPEATABLE READ 격리 수준을 사용하는 트랜잭션의 경우 쿼리 문이 처음 실행될 때만 ReadView가 생성되고 후속 쿼리는 반복적으로 생성되지 않습니다. . 🎜🎜🎜예를 들어, 시스템에서 트랜잭션 ID 10과 20이 실행되는 두 개의 트랜잭션이 있습니다. 🎜🎜🎜🎜🎜

    此刻,表student中id为1的记录得到的版本链表如下所示:

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    假设现在有一个使用REPEATABLE READ隔离级别的事务开始执行:

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    此时执行过程与read committed相同

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    然后再到刚才使用REPEATABLE READ隔离级别的事务中继续查找id为1的记录,如下:

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    这个SELECT2的执行过程如下:

    步骤1:因为当前事务的隔离级别为REPEATABLE READ,而之前在执行SELECT1时已经生成过ReadView了,所以此时直接复用之前的ReadView,之前的ReadView的trx_ids列表的内容就是[10,20],up_limit_id为10, low_limit_id为21 , creator_trx_id为0。
    步骤2:然后从版本链中挑选可见的记录,从图中可以看出,最新版本的列name的内容是’宋八’trx_id值为20,在trx_ids列表内,所以不符合可见性要求,根据roll_pointer跳到下一个版本。
    步骤3:下一个版本的列name的内容是’钱七’,该版本的trx_id值为20,也在trx_ids列表内合要求,继续跳到下一个版本。
    步骤4:下一个版本的列name的内容是’王五’,该版本的trx_id值为10,而trx_ids列表中是包含值为10的事务id的,所以该版本也不符合要求,同理下一个列name的内容是’李四’的版本也不符合要求。继续跳到下个版本。
    步聚5∶下一个版本的列name的内容是’张三’,该版本的trx_id值为80,小于Readview中的up_limit_id值10,所以这个版本是符合要求的,最后返回给用户的版本就是这条列c为‘张三’的记录。
    两次SELECT查询得到的结果是重复的,记录的列c值都是’张三’,这就是可重复读的含义。如果我们之后再把事务id为20的记录提交了,然后再到刚才使用REPEATABLE READ隔离级刷的事务中继续查找这个id为1的记录,得到的结果还是’张三’,具体执行过程大家可以自己分析一下。

    5.3 如何解决幻读

    假设现在表student中只有一条数据,数据内容中,主键id=1,隐藏的trx_id=10,它的undo log如下图所示。

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    假设现在有事务A和事务B并发执行,事务A的事务id为20,事务B的事务id为30。
    步骤1:事务A开始第一次查询数据,查询的SQL语句如下。

    select * from student where id > 1;

    在开始查询之前,MySQL会为事务A产生一个ReadView,此时ReadView的内容如下: trx_ids=[20, 30 ] ,up_limit_id=20 , low_limit_id=31 , creator_trx_id=20。

    因为表student只有一条符合条件 where id>=1 的数据,所以会被查询出来。然后根据ReadView机制,发现该行数据的trx_id=10,小于事务A的ReadView里up_limit_id,这表示这条数据是事务A开启之前,其他事务就已经提交了的数据,因此事务A可以读取到。

    结论:事务A的第一次查询,能读取到一条数据,id=1。

    步骤2∶接着事务B(trx_id=30),往表student中新插入两条数据,并提交事务。

    insert into student(id,name) values(2,&#39;李四&#39;);
    insert into student(id,name) values(3,&#39;王五&#39;);

    此时表student中就有三条数据了,对应的undo如下图所示:

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    3단계∶이후 트랜잭션 A는 반복 읽기 격리 수준 규칙에 따라 현재로서는 ReadView를 재생성하지 않습니다. 이때, Student 테이블에 있는 3개의 데이터는 모두 id>=1이라는 조건을 만족하므로 가장 먼저 검색됩니다. 그런 다음 ReadView 메커니즘에 따라 각 데이터 조각을 트랜잭션 A에서 볼 수 있는지 여부를 판단합니다.
    1) 먼저 앞서 언급한 것처럼 id=1인 데이터는 트랜잭션 A를 통해 확인할 수 있습니다.
    2) 그러면 id=2이고 trx_id=30인 데이터가 있습니다. 이때 트랜잭션 A는 이 값이 up_limit_id와 low_limit_id 사이에 있음을 발견하므로 trx_ids 배열에 30이 있는지 확인해야 합니다. 배열에서 트랜잭션 A의 trx_ids=[20,30]이므로 이는 id=2인 데이터가 트랜잭션 A와 동시에 시작된 다른 트랜잭션에 의해 제출되었음을 의미하므로 이 데이터는 트랜잭션 A에서 볼 수 없습니다.
    3) 마찬가지로 id=3인 이 데이터의 trx_id도 30이므로 트랜잭션 A에서는 볼 수 없습니다.

    MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석

    결론:마지막으로 트랜잭션 A의 두 번째 쿼리는 id=1인 데이터만 쿼리할 수 있습니다. 이는 트랜잭션 A의 첫 번째 쿼리 결과와 동일하므로 팬텀 읽기 현상이 없습니다. 따라서 MySQL의 반복 격리 수준에서는 팬텀 읽기 문제가 없습니다.

    위 내용은 MySQL 다중 버전 동시성 제어 MVCC 인스턴스 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    성명:
    이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제