이 기사에는 MySQL 데이터베이스의 트랜잭션 격리 및 MVCC에 대한 자세한 소개(그림 및 텍스트)가 포함되어 있습니다. 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.
머리말: 트랜잭션은 데이터베이스에 액세스하기 위한 일련의 작업입니다. 데이터베이스 응용 프로그램 시스템은 트랜잭션 세트를 통해 데이터베이스에 대한 액세스를 완료합니다.
트랜잭션은 ISO에서 정한 ACID 원칙을 준수해야 합니다. /IEC. ACID는 원자성(Atomicity), 일관성(Consistency), 격리성(Isolation), 내구성(Durability)의 약어입니다.
1. 원자성
원자성(Atomicity)은 트랜잭션을 의미합니다. 포함된 모든 작업은 성공하거나 실패하고 롤백됩니다. 이전 두 블로그에서 소개한 트랜잭션 기능이므로 트랜잭션 작업이 성공하면 데이터베이스에 완전히 적용되어야 하며, 작업이 실패하면 데이터베이스에 아무런 영향을 미치지 않습니다.
2. 일관성
일관성은 트랜잭션이 데이터베이스를 하나의 일관성 상태에서 다른 일관성 상태로 변환해야 함을 의미합니다.
3. 격리
트랜잭션이 올바르게 제출되기 전에는 이 데이터의 변경 사항이 다른 트랜잭션에 제공될 수 없습니다. 즉, 트랜잭션이 올바르게 커밋되기 전에 가능한 결과가 다른 트랜잭션에 표시되어서는 안 됩니다.
4. 내구성(Durability)
내구성은 트랜잭션이 커밋되면 데이터베이스의 데이터 변경 사항이 영구적이라는 것을 의미합니다. 데이터베이스 시스템에 오류가 발생하더라도 트랜잭션 커밋 작업이 손실되지 않습니다.
2. 트랜잭션의 역할
여러 스레드가 트랜잭션을 시작하여 데이터베이스의 데이터를 조작할 때 데이터베이스 시스템은 각 스레드에서 얻은 데이터의 정확성을 보장하기 위해 격리 작업을 수행할 수 있어야 합니다.
3.
1. 첫 번째 유형의 업데이트: 트랜잭션 A가 취소되면 제출된 트랜잭션 B의 업데이트된 데이터가 덮어쓰여집니다.
2. 두 번째 유형의 업데이트 손실: 트랜잭션 A가 제출한 데이터를 덮어씁니다. 트랜잭션 B로 인해 트랜잭션 B가 작업이 손실됩니다.
3. 더티 읽기: 트랜잭션 A가 트랜잭션 B의 커밋되지 않은 데이터를 읽습니다.
4. 반복 불가능 읽기: 값이 수정되었기 때문에 트랜잭션 A가 여러 번 읽은 값이 다릅니다. 그리고 트랜잭션 B에 의해 커밋되었습니다. .
5. 팬텀 읽기: 트랜잭션 A의 두 읽기 사이에 트랜잭션 B가 데이터를 삽입했습니다.
4. 위의 문제를 해결하는 방법은 무엇입니까?
위의 문제를 해결하기 위해 개발자는 다음 네 가지 유형의 MySQL 데이터베이스 트랜잭션 격리 수준:
1. 커밋되지 않은 읽기(커밋되지 않은 읽기): 더티 읽기가 허용됩니다. 즉, 다른 세션의 커밋되지 않은 트랜잭션에 의해 수정된 데이터를 읽을 수 있습니다.
2. : 제출된 데이터만 읽습니다. Oracle과 같은 대부분의 데이터베이스는 기본적으로 이 수준(반복되지 않는 읽기)으로 설정되어 있습니다.
3.반복 읽기: 반복 읽기. 동일한 트랜잭션 내의 쿼리는 트랜잭션 시작 시 InnoDB 기본 수준에서 일관됩니다. SQL 표준에서 이 격리 수준은 반복 불가능한 읽기를 제거하지만 팬텀 읽기는 여전히 존재하지만 innoDB는 팬텀 읽기를 해결합니다.
4. 직렬화 가능(직렬 읽기): 완전히 직렬화된 읽기, 각 읽기에 필요 테이블 수준 공유 얻기 잠금, 읽기 및 쓰기는 서로 차단됩니다.
격리 수준
더티 읽기 |
비반복성 |
팬텀 읽기 없음 |
|
Read Uncommitted(Uncommitted Read)
가능 | 가능 | Possible |
|
읽기 커밋(읽기로 커밋)
Impossible |
Possible |
Possible |
|
Repeated Read(반복 읽기)
Impossible |
Impossible | 가능 | |
직렬화 가능(직렬 읽기)
불가능 |
불가능 |
불가능 |
|
5. 작은 시도
1. 전역 또는 세션 트랜잭션 격리 수준을 확인하세요
SELECT @@global.tx_isolation, @@tx_isolation;
2. MySQL의 기본 반복 읽기 격리 수준을 수정하면 문제가 논리적으로 해결되지 않습니다. 팬텀리딩에 문제가 있는 걸까요?
다음은 먼저 데이터베이스에 관련된 잠금을 소개합니다.
7. 잠금에 대한 기본 설명
1. 잠금에 대한 소개
데이터베이스의 잠금은 다음과 같은 소프트웨어 메커니즘을 의미합니다. 특정 사용자(프로세스 세션)를 제어하고 방지합니다. 특정 데이터 자원이 점유되면 다른 사용자가 해당 사용자의 데이터 작업에 영향을 미치거나 데이터 비무결성 및 비일관성 문제를 일으키는 조치를 취합니다. 2. 잠금 수준
잠금 수준에 따라 잠금은 공유 잠금과 단독 잠금으로 구분됩니다.
공유 잠금(읽기 잠금)
- 동일한 데이터에 대해 서로 영향을 주지 않고 동시에 여러 읽기 작업을 수행할 수 있습니다. 공유 잠금은 UPDATE 작업이 제출되기 전에만 잠기며, 다른 트랜잭션은 최신 레코드만 얻을 수 있지만 UPDATE 작업을 수행할 수는 없습니다.
배타적 잠금(쓰기 잠금)
- 현재 쓰기 작업이 완료되기 전에 다른 쓰기 잠금과 읽기 잠금을 차단합니다.
3. 잠금 세분성 잠금 세분성에 따라 잠금은 테이블 수준 잠금, 행 수준 잠금, 페이지 수준 잠금으로 나눌 수 있습니다.
행 수준 잠금
- 은 비용이 많이 들고 잠금 속도가 느리며 교착 상태가 발생하고 잠금 강도가 가장 낮으며 잠금 충돌 가능성이 가장 낮고 동시성이 높습니다.
테이블 수준 잠금
- 은 오버헤드가 낮고 잠금이 빠르며 교착 상태가 없고 잠금 강도가 높으며 충돌 가능성이 높으며 동시성이 낮습니다.
페이지 잠금
- 비용과 잠금 시간은 테이블 잠금과 행 잠금 사이에 있으며 교착 상태가 발생하며 잠금 강도는 테이블 수준 잠금과 행 수준 잠금 사이에 있으며 동시성은 평균입니다.
8. 비관적 잠금 및 낙관적 잠금
8.1 비관적 잠금
1. 기본 아이디어: 항상 최악의 시나리오를 가정하고 데이터를 얻을 때마다 다른 사람이 이를 수정할 것이라고 생각하므로 데이터를 얻을 때마다 잠겨 있으므로 다른 사람이 데이터를 가져오려고 하면 잠금을 얻을 때까지 차단됩니다. (공유 리소스는 한 번에 하나의 스레드에서만 사용되며 다른 스레드는 차단되고 리소스는 다른 스레드로 전송됩니다.) 사용 후). 이러한 잠금 메커니즘은 행 잠금, 테이블 잠금, 읽기 잠금, 쓰기 잠금 등과 같은 기존 관계형 데이터베이스에서 사용되며, 이는 모두 작업 전에 잠기므로 실제로 충돌이 발생하더라도 잠금이 사용됩니다. 기구.
2. 비관적 잠금 기능:
다른 거래가 이러한 레코드를 읽고 업데이트하지 못하도록 읽기 레코드를 잠급니다. 이 거래가 끝날 때까지 다른 거래가 차단됩니다.
- 비관적 잠금은 읽기 데이터의 일관성을 보장하고 수정 손실을 방지하기 위해 데이터베이스의 트랜잭션 격리 기능을 사용하여 리소스를 독점적으로 점유합니다.
- 비관적 잠금은 비관적 잠금의 요구 사항을 완전히 충족하는 반복 읽기 트랜잭션을 사용할 수 있습니다.
- 8.2 낙관적 잠금
1. 기본 아이디어: 항상 최상의 상황을 가정합니다. 데이터를 얻으러 갈 때마다 다른 사람이 데이터를 수정하지 않을 것이라고 생각하므로 잠그지는 않지만 업데이트할 때 판단하게 됩니다. . 이 기간 동안 다른 사람이 이 데이터를 업데이트했는지 여부는
버전 번호 메커니즘 및 CAS 알고리즘을 사용하여 구현할 수 있습니다. 낙관적 잠금은 처리량을 향상시킬 수 있는 다중 읽기 애플리케이션 유형에 적합합니다. 2. 설명: 낙관적 잠금은 아무것도 잠그지 않습니다. 즉, 데이터베이스의 트랜잭션 메커니즘에 의존하지 않습니다. . 낙관적 잠금 잠금은 전적으로 애플리케이션 시스템 수준에 있습니다. 따라서 낙관적 잠금을 사용하는 경우 데이터베이스에 버전 필드를 추가해야 합니다. 그렇지 않으면 모든 필드를 비교할 수만 있지만 부동 소수점 유형은 비교할 수 없기 때문에 실제로 버전 필드 없이는 불가능합니다
8.3 버전 번호 메커니즘
일반적으로 데이터 테이블에 데이터 버전 번호 필드를 추가하여 데이터가 수정된 횟수를 나타냅니다. 버전 값은 1씩 증가합니다. 스레드 A가 데이터 값을 업데이트하려고 하면 데이터를 읽는 동안 버전 값도 읽습니다. 업데이트를 제출할 때 방금 읽은 버전 값이 현재 데이터베이스의 버전 값과 동일한 경우에만 업데이트하고, 그렇지 않으면 다시 시도하세요. . 업데이트가 성공할 때까지 업데이트 작업을 수행합니다.
8.4 CAS 알고리즘
1. 핵심 아이디어: 비교하고 교환합니다. 즉, 비교하고 교환합니다.
2. 프로세스: 스레드 A가 메모리에 있는 변수 이름의 값을 수정할 것이라고 가정합니다. 따라서 스레드 A는 이전에 읽은 이름 변수의 값과 현재 이름의 값을 비교합니다. 마찬가지로 변수 값이 수정되지 않았으므로 업데이트 및 수정이 가능하다는 의미입니다. 그렇지 않으면 업데이트가 실패합니다.
9. MySQL의 반복 읽기 트랜잭션 격리 수준으로 돌아가기
앞서 언급한 것처럼 MySQL은 다음을 구현합니다. 그러나 반복 읽기를 사용하는 MySQL 데이터베이스의 트랜잭션 격리 조건에서는 MySQL에서 MVCC(Multiple Version Concurrency Control)를 사용하여 팬텀 읽기가 발생하지 않습니다.
통제.9.1名词简析:
1.MVCC:是multiversion concurrency control的简称,也就是多版本并发控制,是个很基本的概念。MVCC的作用是让事务在并行发生时,在一定隔离级别前提下,可以保证在某个事务中能实现一致性读,也就是该事务启动时根据某个条件读取到的数据,直到事务结束时,再次执行相同条件,还是读到同一份数据,不会发生变化(不会看到被其他并行事务修改的数据)。
2.read view:InnoDB MVCC使用的内部快照的意思。在不同的隔离级别下,事务启动时(有些情况下,可能是SQL语句开始时)看到的数据快照版本可能也不同。在上面介绍的几个隔离级别下会用到 read view。
3.快照读: 就是所谓的根据read view去获取信息和数据,不会加任何的锁。
4.当前读:前读会获取得到所有已经提交数据,按照逻辑上来讲的话,在一个事务中第一次当前读和第二次当前读的中间有新的事务进行DML操作,这个时候俩次当前读的结果应该是不一致的,但是实际的情况却是在当前读的这个事务还没提交之前,所有针对当前读的数据修改和插入都会被阻塞,主要是因为next-key lock解决了当前读可能会发生幻读的情况。
next-key lock当使用主键索引进行当前读的时候,会降级为record lock(行锁)
9.2 Read view详析
InnoDB支持MVCC多版本控制,其中READ COMMITTED和REPEATABLE READ隔离级别是利用consistent read view(一致读视图)方式支持的。所谓的consistent read view就是在某一时刻给事务系统trx_sys打snapshot(快照),把当时的trx_sys状态(包括活跃读写事务数组)记下来,之后的所有读操作根据其事务ID(即trx_id)与snapshot中trx_sys的状态做比较,以此判断read view对事务的可见性。
REPEATABLE READ隔离级别(除了GAP锁之外)和READ COMMITTED隔离级别的差别是创建snapshot时机不同。REPEATABLE READ隔离级别是在事务开始时刻,确切的说是第一个读操作创建read view的时候,READ COMMITTED隔离级别是在语句开始时刻创建read view的。这就意味着REPEATABLE READ隔离级别下面一个事务的SELECT操作只会获取一个read view,但是READ COMMITTED隔离级别下一个事务是可以获取多个read view的。
创建/关闭read view需要持有trx_sys->mutex,会降低系统性能,5.7版本对此进行优化,在事务提交时session会cache只读事务的read view。
9.3 read view 判断当前版本数据项是否可见
在InnoDB中,创建一个新事务的时候,InnoDB会将当前系统中的活跃事务列表(trx_sys->trx_list)创建一个副本(read view),副本中保存的是系统当前不应该被本事务看到的其他事务id列表。当用户在这个事务中要读取该行记录的时候,InnoDB会将该行当前的版本号与该read view进行比较。
具体的算法如下:
设该行的当前事务id为trx_id,read view中最早的事务id为trx_id_min, 最迟的事务id为trx_id_max。
如果trx_id如果trx_id>trx_id_max的话,那么表明该行记录所在的事务在本次新事务创建之后才开启,所以该行记录的当前值不可见。
如果trx_id_min
从该行记录的DB_ROLL_PTR指针所指向的回滚段中取出最新的undo-log的版本号的数据,将该可见行的值返回。
需要注意的是,新建事务(当前事务)与正在内存中commit 的事务不在活跃事务链表中。
在具体多版本控制中我们先来看下源码:
函数:read_view_sees_trx_id。
read_view中保存了当前全局的事务的范围:
【low_limit_id, up_limit_id】
1.当行记录的事务ID小于当前系统的最小活动id,就是可见的。
if (trx_id up_limit_id) {
return(TRUE);
}
2.当行记录的事务ID大于当前系统的最大活动id(也就是尚未分配的下一个事务的id),就是不可见的。
if (trx_id >= view->low_limit_id) {
return(FALSE);
}
3.当行记录的事务ID在活动范围之中时,判断是否在活动链表中,如果在就不可见,如果不在就是可见的。
for (i = 0; i <p><strong>Read view 图解</strong>:<br></p><p><img src="https://img.php.cn/upload/image/428/162/665/1553653110536794.jpg" title="1553653110536794.jpg" alt="MySQL 데이터베이스의 트랜잭션 격리 및 MVCC에 대한 자세한 소개(그림 및 텍스트)"></p><p style="max-width:90%">结语:笔者水平有限,文中如有不妥,请大家多多指教,MySQL数据库事务机制还有很多需要深入研究的,我们仍需不断钻研。</p><p>本篇文章到这里就已经全部结束了,更多其他精彩内容可以关注PHP中文网的<a href="http://www.php.cn/course/list/51.html" target="_blank">MySQL视频教程</a>栏目!</p><p></p>
위 내용은 MySQL 데이터베이스의 트랜잭션 격리 및 MVCC에 대한 자세한 소개(그림 및 텍스트)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!