작동 중인 MySQL: 잠금

이미지 설명을 추가하세요

동시 시나리오

MySQL을 배울 때 우리는 종종 사물의 4가지 특성인 원자성, 일관성, 격리성, 내구성을 언급합니다. 그렇다면 격리는 어떻게 달성됩니까?

격리의 본질은 SQL 문이 직렬로 실행되는 경우 동시성을 제어하는 ​​것입니다. 그러면 데이터베이스의 4가지 특성에 격리 개념이 없고 더티 읽기, 반복 불가능 읽기 및 팬텀 읽기와 같은 문제가 없을 것입니다.

데이터베이스에는 쓰기-쓰기, 읽기-읽기, 읽기-쓰기 및 쓰기-읽기의 4가지 종류의 동시 작업만 있습니다.

쓰기 쓰기

트랜잭션 A가 레코드를 업데이트할 때 트랜잭션 B가 동일한 레코드를 동시에 업데이트할 수 있습니까?

대답은 확실히 아니오, 그렇지 않으면 더티 쓰기의 문제를 일으킬 것입니다 .더티 쓰기 를 피하는 방법? 잠그는 게 답이다

읽고 또 읽어라

MySQL 읽기 작업은 기본적으로 잠겨 있지 않으므로 병렬로 읽을 수 있습니다.

읽기-쓰기 및 쓰기-읽기

다양한 시나리오에서 동시 작업의 다양한 허용 수준을 기반으로 MySQL은 격리 개념을 개발했습니다 . 비즈니스 시나리오에 따라 격리 수준을 선택할 수 있습니다.

√ 일어날 것, ×는 일어나지 않을 것

격리 수준 더러운 읽기 반복 불가능한 읽기 환각
커밋되지 않은 읽기
커밋 읽기 ×
반복 가능한 읽기 × ×
직렬화 가능(직렬화 가능) × × ×

MySQL의 잠금

행 수준 잠금

InnoDB 스토리지 엔진에는 두 가지 유형의 행 수준 잠금이 있습니다.

  1. 공유 잠금 (공유 잠금, S 잠금이라고 함), 트랜잭션이 레코드를 읽어야 할 때 레코드를 변경하려면 먼저 S 잠금을 획득해야 합니다.
  2. 배타적 잠금 (Exclusive Lock, X 잠금이라고 함), 트랜잭션이 레코드를 변경하려면 레코드의 X 잠금을 먼저 획득해야 합니다.

트랜잭션 T1이 레코드의 S 잠금을 획득하면 트랜잭션 T2도 이 레코드에 액세스합니다. 트랜잭션 T2가 이 레코드의 S 잠금을 다시 획득하려고 하면 성공할 수 있습니다. 이러한 상황을 잠금 호환성이라고 합니다. 트랜잭션 T2가 이 레코드의 X 잠금을 다시 획득하려는 경우 트랜잭션 T1이 S를 커밋할 때까지 이 작업이 차단됩니다. 잠금 해제

트랜잭션 T1이 레코드의 X 잠금을 획득한 경우 트랜잭션 T2가 다음에 레코드의 S 잠금 또는 X 잠금을 획득하기를 원하는지 여부는 트랜잭션 1이 커밋될 때까지 차단되며, 이를 잠금 비호환성이라고 합니다.

여러 트랜잭션이 동시에 레코드를 읽을 수 있습니다. 즉, 공유 잠금은 상호 배타적이지 않지만 공유 잠금은 배타적 잠금을 차단합니다. 배타적 잠금 간의 상호 배제

S 잠금과 X 잠금의 호환성 관계는 다음과 같습니다.

호환성 X 잠금 에스 락
X 잠금 상호 배타적 상호 배타적
에스 락 상호 배타적 호환

업데이트, 삭제 및 삽입은 관련된 데이터에 배타적 잠금을 자동으로 추가하고 select 문은 기본적으로 잠금을 추가하지 않습니다.

어떤 상황에서 읽기 작업이 잠기나요?

  1. 선택 ... 공유 모드에서 잠금, 읽기 레코드에 S 잠금 추가
  2. 업데이트를 위해 ...를 선택하고 읽기 레코드에 X 잠금을 추가합니다.
  3. 트랜잭션의 레코드 읽기, 읽기 레코드에 S 잠금 추가
  4. 트랜잭션 격리 수준은 SERIALIZABLE 아래에 있으며 읽기 레코드에 S 잠금이 적용됩니다.

InnoDB에는 행 잠금을 위한 세 가지 알고리즘이 있습니다.

  1. 레코드 잠금: 단일 레코드 잠금
  2. 간격 잠금: 간격 잠금, 레코드 앞의 간격을 잠그고 레코드 삽입을 허용하지 않습니다.
  3. Next-key Lock: 데이터와 데이터 앞의 공백을 동시에 잠급니다. 즉, 데이터와 데이터 앞의 공백 모두 레코드를 삽입할 수 없습니다.

시연할 데모 작성

CREATE TABLE `girl` (
  `id` int(11) NOT NULL,
  `name` varchar(255),
  `age` int(11),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into girl values
(1, '西施', 20),
(5, '王昭君', 23),
(8, '貂蝉', 25),
(10, '杨玉环', 26),
(12, '陈圆圆', 20);

녹음 잠금

단일 레코드 잠금

예를 들어 id 값이 8인 데이터에 Record Lock을 추가하면 개략도는 다음과 같습니다.

여기에 이미지 설명 삽입
Record Lock도 S락과 X락으로 나뉘며 호환성은 앞서 설명한 것과 같다.

SQL 실행에 추가되는 잠금의 종류는 트랜잭션의 격리 수준 및 실행 중에 사용되는 인덱스(클러스터형 인덱스, 비클러스터형 인덱스 등)와 같은 많은 조건에 의해 제한되므로 분석되지 않습니다. 자세히 설명하지만 몇 가지 간단한 예가 제공됩니다.

-- READ UNCOMMITTED/READ COMMITTED/REPEATABLE READ 利用主键进行等值查询
-- 对id=8的记录加S型Record Lock
select * from girl where id = 8 lock in share mode;

-- READ UNCOMMITTED/READ COMMITTED/REPEATABLE READ 利用主键进行等值查询
-- 对id=8的记录加X型Record Lock
select * from girl where id = 8 for update;

갭 잠금

레코드 앞의 간격을 잠그고 레코드 삽입을 허용하지 않습니다.

MySQL은 MVCC 및 반복 가능한 읽기 격리 수준에서 잠금을 통해 팬텀 읽기 문제를 해결할 수 있습니다.

현재 읽기: 잠긴
스냅샷 읽기: MVCC

그러나 어떻게 잠글 수 있습니까? 이러한 팬텀 레코드는 처음 읽기 작업을 수행할 때 존재하지 않기 때문에 Record Lock을 추가할 수 있는 방법이 없습니다.

여기에 이미지 설명 삽입

예를 들어, 트랜잭션이 id=8인 레코드에 갭 잠금을 추가하면 다른 트랜잭션이 id=8인 레코드, 즉 id 값을 갖는 레코드 이전의 갭에 새 레코드를 삽입할 수 없음을 의미합니다. 간격 (5, 8)에서 허용되지 않습니다.즉시 삽입을 허용합니다. 간격 잠금이 있는 트랜잭션이 커밋될 때까지 (5, 8) 간격의 id 값이 있는 레코드를 제출할 수 없습니다.

다음 SQL 잠금 프로세스를 살펴보겠습니다.

-- REPEATABLE READ 利用主键进行等值查询
-- 但是主键值并不存在
-- 对id=8的聚集索引记录加Gap Lock
SELECT * FROM girl WHERE id = 7 LOCK IN SHARE MODE;

id=7인 레코드가 존재하지 않기 때문에 팬텀 읽기(Phantom Reading) 현상을 방지하기 위해(동일한 트랜잭션에서 동일한 명령문을 실행하여 얻은 결과 집합에서 id=7인 레코드를 피하기 위해) 다른 트랜잭션을 방지해야 합니다. 현재 트랜잭션이 커밋되기 전에 id를 삽입하는 것에서 = 7 레코드, 이때 id = 8인 레코드에 Gap Lock을 추가할 수 있습니다. 즉, 다른 트랜잭션이 id 값을 가진 새 레코드를 삽입할 수 없습니다. 간격 (5, 8).

질문을 드리겠습니다. Gap Lock은 레코드 앞의 간격만 잠글 수 있으므로 마지막 레코드 뒤의 간격을 잠그는 방법은 무엇입니까?

실제로 mysql 데이터는 페이지에 저장되며 각 페이지에는 2개의 의사 레코드가 있습니다.

  1. 페이지에서 가장 작은 레코드를 나타내는 최하위 레코드
  2. 페이지에서 가장 큰 레코드를 나타내는 upremum 레코드

다른 트랜잭션이 id 값이 (12, +∞) 범위에 있는 레코드를 삽입하는 것을 방지하기 위해 id=12 레코드가 위치한 페이지의 Supremum 레코드에 gap lock을 추가할 수 있습니다. 다른 트랜잭션이 (12) , +∞) 이 간격에 대한 새 레코드에 id 값을 삽입하는 것을 방지할 수 있습니다.

다음 키 잠금

동시에 데이터와 데이터 앞의 간격을 잠그십시오. 즉, 데이터와 데이터 앞의 간격은 레코드를 삽입
할 수 없으므로 Next-key Lock=Record Lock+Gap을 이해할 수 있습니다. 잠그다
여기에 이미지 설명 삽입

-- REPEATABLE READ 利用主键进行范围查询
-- 对id=8的聚集索引记录加S型Record Lock
-- 对id>8的所有聚集索引记录加S型Next-key Lock(包括Supremum伪记录)
SELECT * FROM girl WHERE id >= 8 LOCK IN SHARE MODE;

팬텀 읽기 문제를 해결하기 위해서는 다른 트랜잭션이 id>=8인 레코드를 삽입하는 것을 금지해야 하므로

  • id=8인 클러스터형 인덱스 레코드에 S 유형 레코드 잠금 추가
  • id>8(Supremum 의사 레코드 포함)을 가진 모든 클러스터형 인덱스 레코드에 S 유형 다음 키 잠금 추가

더 나은 이해를 드리기 위해

테이블 레벨 잠금

테이블 잠금은 S 잠금과 X 잠금으로 나뉩니다.

테이블에서 select, insert, update 및 delete 문을 실행할 때 innodb 스토리지 엔진은 테이블 수준 S 잠금 또는 X 잠금을 테이블에 추가하지 않습니다.

ALTER TABLE 및 DROP TABLE과 같은 일부 DDL 문을 테이블에서 실행하면 테이블에 X 잠금이 추가되므로 이 테이블에서 SELECT INSERT UPDATE DELETE와 같은 명령문을 실행할 때 다른 트랜잭션이 차단됩니다.

시스템 변수 autocommit=0이고 innodb_table_locks = 1일 때 InnoDB 스토리지 엔진이 제공하는 테이블 t의 S 잠금 또는 X 잠금을 수동으로 얻으려면 다음을 작성할 수 있습니다.

테이블 t에 테이블 수준 S 잠금 추가

lock tables t read

테이블 t에 테이블 수준 X 잠금 추가

lock tables t write

트랜잭션이 테이블에 S 잠금을 추가하면

  • 다른 트랜잭션은 테이블에 대한 S 잠금을 계속 획득할 수 있습니다.
  • 다른 트랜잭션은 테이블의 특정 레코드에 대해 계속 S 잠금을 획득할 수 있습니다.
  • 다른 트랜잭션은 테이블에 대한 X 잠금을 계속 획득할 수 없습니다.
  • 다른 트랜잭션은 테이블의 일부 레코드에 대해 X 잠금을 계속 획득할 수 없습니다.

트랜잭션이 테이블에 X 잠금을 추가하면

  • 다른 트랜잭션은 테이블에 대한 S 잠금을 계속 획득할 수 없습니다.
  • 다른 트랜잭션은 테이블의 일부 레코드에 대해 S 잠금을 계속 얻을 수 없습니다.
  • 다른 트랜잭션은 테이블에 대한 X 잠금을 계속 획득할 수 없습니다.
  • 다른 트랜잭션은 테이블의 일부 레코드에 대해 X 잠금을 계속 획득할 수 없습니다.

따라서 온라인 테이블을 수정할 때 많은 트랜잭션이 차단되므로 주의해야 합니다 .현재 온라인 테이블을 수정하는 성숙한 방법이 많이 있으므로 반복하지 않겠습니다.

테이블 수준에는 IS 잠금(의도된 공유 잠금)과 IX 잠금(의도된 배타적 잠금)도 있습니다.

사물이 레코드에 S 잠금을 설정하면 해당 레코드에 해당하는 테이블에도 IS 잠금이 설정됩니다(IS 잠금은 테이블 수준 잠금입니다). 사물이 레코드에 X 잠금을 설정하면 레코드에 해당하는 테이블에 대한 IX 잠금(IX 잠금) 잠금이 테이블 수준 잠금임)

트랜잭션 격리 수준 구현

RR RC
노멀 셀렉트 MVCC MVCC
잠금 선택 및 업데이트
선택 ... 샤프 모드
에서 선택 ... 업데이트
삽입
삭제
업데이트
녹음 잠금
간격 잠금
다음 키 잠금
녹음 잠금
*

참조 블로그

[1] https://souche.yuque.com/bggh1p/8961260/gyzlaf
[2] https://zhuanlan.zhihu.com/p/35477890
각종 자물쇠 분류
[3 ] https://www.hacker66.me /detail/ZYXWPXH.html

рекомендация

отblog.csdn.net/zzti_erlie/article/details/123743716