💻 computer science/📦 database

MySQL - 트랜잭션 격리 수준 실습

beomsic 2024. 5. 11. 21:24

⚙️ 실습 세팅

트랜잭션 격리 수준을 실습해보기 위해서 테이블을 만들고 데이터를 넣어두었다.

 

👤 Member Table

CREATE TABLE MEMBER (
  id bigint auto_increment primary key,
  name varchar(255) not null,
  constraint UK_name unique (name)
); 

 

➕ 데이터 추가

INSERT INTO MEMBER (id, name) VALUES(1, 'Beomsic');
INSERT INTO MEMBER (id, name) VALUES(2, 'Beomseok');
INSERT INTO MEMBER (id, name) VALUES(3, 'KO');

 

💻 2개의 데이터베이스 세션 설정

set autocommit = FALSE; // 현재 세션의 자동 커밋 비활성

SELECT @@tx_isolation; // 현재 세션 격리 수준 확인

각각의 세션에서 자동 커밋 모드를 꺼준다.

 

🧩 SERIALIZABLE

 

🔍 데이터 조회

 

사용자 A 사용자 B
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  START TRANSACTION;
  SELECT * FROM member WHERE id >= 3;
- 1건 조회 성공
START TRANSACTION;   
SELECT * FROM member WHERE id >= 3;
- 1건 조회 성공
 
COMMIT;  
  COMMIT;

 

SERIALIZABLE 은 일반적인 SELECT 작업에서도 대상 레코드에 넥스트 키 락을 읽기 잠금으로 건다

따라서, 한 트랜잭션에서 읽은 레코드를 다른 트랜잭션에서도 조회할 수 있다.

 

 

🔄 데이터 수정

 

사용자 A 사용자 B
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  START TRANSACTION;
  SELECT * FROM member WHERE id >= 3;
- 1건 조회 성공
START TRANSACTION;   
UPDATE MEMBER SET name = ‘KOBEOMSEOK’ WHERE id = 3;
- 잠금 대기 상태 (A)
 
  COMMIT; (B)
UPDATE 쿼리 실행 완료  
COMMIT;  

 

 

🔒 (A) 잠금 대기 상태

 

 

 

📍 COMMIT 이후 (B)

 

 

✔️ 결과

SELECT * FROM MEMBER WHERE id >= 3;

// id : 3 name : KOBEOMSEOK

 

SERIALIZABLE 격리수준에서 한 트랜잭션이 읽은 데이터를 다른 트랜잭션에서 수정하는 것은 불가능하다.

  • 이유 : 읽기 잠금에 의해 변경을 하기 위해서는 락을 획득해야 하기 때문

 

🧩 REPEATABLE READ

 

🏃 REPEATABLE READ 정상 작동

사용자 A 사용자 B
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
  START TRANSACTION;
  SELECT * FROM member WHERE id >= 3;
- 1건 조회 성공 
START TRANSACTION;  
UPDATE MEMBER SET name = ‘KO’ WHERE id = 3;
- 업데이트 성공
 
COMMIT;  
  SELECT * FROM member WHERE id >= 3;
- 1건 조회 성공
- name : KOBEOMSEOK(변경 전 데이터)

 

REPEATABLE READ에서는 기본적으로 다른 트랜잭션에서 변경한 내용이 보이지 않는다.

 

👻 Phantom Read 발생 (부정합 문제)

사용자 A 사용자 B
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
  START TRANSACTION;
  SELECT * FROM member WHERE id >= 3;
- 1건 조회 성공
START TRANSACTION;   
INSERT INTO MEMBER (id, name) VALUES (4, 'phantomname');
- 성공
 
COMMIT;  
  SELECT * FROM member WHERE id >= 3;
- 2건 조회 (MySQL 이 아닌 경우)
- 1건 조회 (MySQL)

 

🧩 READ COMMITTED

🏃 READ COMMITTED 정상 작동

사용자 A 사용자 B
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;  
UPDATE MEMBER SET name = ‘KKK’ WHERE id = 3;
- 업데이트 성공
 
  SELECT * FROM member WHERE id >= 3;
- 1건 조회 성공
- 변경 전 데이터
COMMIT;  
  SELECT * FROM member WHERE id >= 3;
- 1건 조회 성공
- name : KKK(변경 후 데이터)

 

 

💣 Non-Repeatable Read 발생 (부정합 문제)

사용자 A 사용자 B 
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
  START TRANSACTION;
  SELECT * FROM member WHERE name = ‘KOKO’
- 0건 조회 성공
START TRANSACTION;  
UPDATE MEMBER SET name = ‘KOKO’ WHERE Id = 3;
- 성공
 
COMMIT;  
  SELECT * FROM member WHERE name = ‘KOKO’
- 1건 조회

 

READ COMMITTED 에서 한 트랜잭션내에서 반복 읽기를 수행할 때, 다른 트랜잭션의 커밋 여부에 따라 조회 결과가 달라진다.

  • Non-Repeatable Read

 

🧩 READ UNCOMMITTED

 

💣 Dirty Read 발생 (부정합 문제)

사용자 A 사용자 B
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;  
  SELECT * FROM member WHERE name = ‘KKK’
- 0건 조회 성공
UPDATE MEMBER SET name = ‘KKK’ WHERE Id = 3;
- 성공
 
  SELECT * FROM member WHERE name = ‘KKK’
- 1건 조회

 

READ COMMITTED 에서 한 트랜잭션내에서 반복 읽기를 수행할 때, 다른 트랜잭션의 커밋 여부에 따라 조회 결과가 달라진다.

  • Non-Repeatable Read

 

📕 참고자료

[MySQL] 트랜잭션 격리 수준과 부정합 문제들(Dirty Read, Non-Repeatable Read, Phantom Read) 실습해보기