[Database] 5. 트랜잭션의 격리 수준과 락

1. 트랜잭션의 격리성

지난 시간에 트랜잭션의 특징 ACID에 대해 알아보았다. 그중 Isolation, 격리성을 보장하기 위한 두 가지 개념(격리 수준, 락)이 등장했다.

 

[Database] 4. 트랜잭션과 무결성

1. 트랜잭션이란? 1.1. 트랜잭션의 정의 - 데이터베이스에서 하나의 논리적 기능을 수행하기 위한 작업의 단위 - 데이터베이스의 상태를 변화시킬 때, 이를 완전하게 수행하거나 하나도 수행하지

ssoyeong.tistory.com

 

1.1. 동시성 제어

- 여러 트랜잭션이 동시에 데이터베이스에 접근하여 작업을 수행할 때 발생할 수 있는 문제를 관리하고 해결하는 것

- 즉, 트랜잭션의 실행 순서를 제어하는 기법

- 데이터 일관성과 무결성을 보장하고, 여러 트랜잭션이 동시에 실행될 수 있도록 도와줌

- 동시성과 일관성은 반비례 관계 (동시에 여러 사용자가 같은 데이터를 계속 변경하면, 데이터 일관성은 낮아짐)

- 동시성 제어를 위해 트랜잭션의 격리 수준을 설정하고 락을 사용하는 방법 등이 존재함

 

2. 격리 수준

- 격리 수준은 여러 트랜잭션이 동시에 실행될 때, 각 트랜잭션의 결과가 다른 트랜잭션에 영향을 미치지 않도록 보장하는데 사용됨

- 격리 수준은 4단계로 나뉘고, 각 단계마다 나타나는 현상(문제)이 있음

- 높은 격리 수준은 데이터의 일관성을 유지할 수 있지만 동시성을 감소시킬 수 있음

 

2.1. 격리 수준에 따라 발생하는 현상

2.1.1. Phantam Read

- 팬텀 리드

- 한 트랜잭션 내에서 동일한 쿼리를 보냈을 때 해당 조회 결과가 다른 현상

- 첫번째 쿼리에 없던 유령 레코드가 두번째 쿼리에서 나타나는 현상

 

ex) 트랜잭션 A에서 회원 테이블을 SELECT하는 쿼리를 실행함
      트랜잭션 B에서 회원 테이블에 데이터를 INSERT함

      트랜잭션 A에서 또다시 SELECT를 하면 이전과 결과가 달라짐

 

2.1.2. Non Repeatable Read

- 반복 가능하지 않은 조회

- 한 트랜잭션 내의 같은 행에 두 번 이상 조회가 발생했는데, 그 값이 다른 현상

 

ex) 사용자 A가 회원 수를 100이라는 값으로 읽었는데

      사용자 B가 회원 수를 99라는 값으로 변경하면 (커밋까지 함)

      사용자 A가 또다시 조회했을 때 100이 아닌 99라는 값을 읽게 됨

 

- 팬텀 리드는 동일한 쿼리를 두 번 실행했을 때, 반복 가능하지 않은 조회는 동일한 데이터를 두 번 읽을 때의 현상을 나타냄

 

2.1.3. Dirty Read

- 더티 리드

- 한 트랜잭션이 실행 중일 때 다른 트랜잭션에 의해 수정되었지만 아직 '커밋되지 않은' 행의 데이터를 읽을 수 있는 현상

- 반복 가능하지 않은 조회와 유사함

- 또한 두번째로 읽은 데이터가 이후 롤백되면, 읽은 값이 더 이상 유효하지 않게 됨

 

ex) 사용자 A가 회원 수를 100이라는 값으로 읽었는데

      사용자 B가 회원 수를 99라는 값으로 변경하고 (커밋하지 않음)

      사용자 A가 또다시 조회했을 때 100이 아닌 99라는 값을 읽게 됨

 

ex) 트랜잭션 A에서 데이터를 수정하고 아직 커밋하지 않음

      트랜잭션 B에서 해당 데이터를 읽음

      트랜잭션 A에서 아직 커밋하지 않은 변경을 읽어옴

->  트랜잭션 A가 롤백되면, 트랜잭션 B가 읽은 데이터는 더 이상 유효하지 않게 됨

 

2.2. 격리 수준 4단계

2.2.1. Uncommitted Read

- 다른 트랜잭션에서 커밋되지 않은 데이터에 접근할 수 있음

- 가장 낮은 격리 수준으로, 일반적으로 사용하지 않는 격리수준임

 

10번 트랜잭션이 '박기영' 데이터를 '박경'으로 UPDATE함

13번 트랜잭션이 아직 COMMIT 되지 않은 데이터에 접근해서 '박경' 데이터를 읽을 수 있음

근데 10번 트랜잭션이 ROLLBACK 된다면, 13번 트랜잭션에는 Dirty Read 현상이 발생함

 

2.2.2. Committed Read

- 다른 트랜잭션이 커밋한 변경 사항만 읽을 수 있음

- MySQL을 제외하고 일반적으로 사용하는 격리 수준

- 실제 테이블에서 값을 가져오는 것이 아니라 Undo 영역에 백업된 레코드에서 값을 가져옴

 

트랜잭션 13에서는 '박경'이 아닌 Undo 영역에서 '박기영' 데이터를 읽어옴

Dirty Read 현상이 발생하지 않음

Undo 영역이란?

이전 포스팅에서 지속성에 대해 공부할 때, 트랜잭션의 결과를 영구적으로 저장하고 보존하는 것으로, 로그를 반드시 남겨 복구할 수 있어야 한다는 의미였다.

로그는 크게 오류 복구에 사용되는 Redo 로그트랜잭션 롤백에 사용되는 Undo 로그가 있다.

 

그런데 Undo 영역이라고 말하는 이유는?

Undo Log가 Undo Log Buffer 형태로 메모리에 저장되고, 특정 시점에 디스크에 저장된 Undo Log File에 I/O 작업으로 쓰여지기 때문

데이터에 변경 사항이 생길 때마다 디스크에 I/O 작업을 하는 것보다 버퍼에 저장해두고 처리하는 것이 속도와 리소스 측면에서 유리함

 

다시 Read Committed로 돌아가서,

이는 Non Repeatable Read 현상이 발생할 수 있음

 

10번 트랜잭션이 커밋하면, 13번 트랜잭션은 처음에는 '박기영'으로 읽고 이후에는 '박경'으로 읽게 됨

 

2.2.3. Repeatable Read

- 동일한 쿼리를 실행했을 때 결과가 항상 동일하게 유지됨

- MySQL의 InnoDB 스토리지 엔진에서 기본적으로 사용되는 격리 수준

- 각 트랜잭션은 시작 시점에서 "데이터 스냅샷"을 만들고 트랜잭션마다 고유한 번호가 매겨짐

- 번호를 기준으로, 자신보다 앞선 번호의 트랜잭션 데이터에만 접근할 수 있음

 

10번 트랜잭션은 10번보다 앞선 트랜잭션에서 커밋한 데이터만 읽을 수 있으므로, 13번 트랜잭션에서 변경한 내용은 조회할 수 없음

그러나 8번 트랜잭션에서 데이터를 변경한다면, 10번 트랜잭션에서 이전과 다른 결과를 얻는 Phantom Read 현상이 발생할 수 있음

하지만 MySQL InnoDB에서는 Next Key Lock을 통해 Repeatable Read 격리 수준에서도 Phantom Read가 발생하지 않음

 

2.2.4. Serializable

- 가장 높은 격리 수준으로, 트랜잭션을 무조건 순차적으로 실행함

- 동시 처리가 불가능해 처리 속도가 느려짐

- SELECT 쿼리 실행 시 Shared Lock, INSERT, UPDATE, DELETE 쿼리 실행 시 Exclusive Lock을 통해 구현됨

 

3. 락

- 락은 트랜잭션 처리의 순차성을 보장하기 위한 방법

- 트랜잭션은 작업을 시작하기 전에 필요한 데이터에 대해 적절한 락을 요청하고, 해당 락이 획득될 때까지 기다림

- 이후 작업을 수행하고 완료되면, 락을 해제하여 다른 트랜잭션이 해당 데이터에 접근할 수 있게 함

 

3.1. Shared Lock

- 데이터를 읽을 때 사용되는 락 (SELECT)

- 하나의 데이터를 여러 트랜잭션이 동시에 읽을 수 있음

- shared lock이 해제될 때까지, 데이터에 exclusive lock을 걸 수 없음

 

3.2. Exclusive Lock

- 데이터를 변경할 때 사용되는 락 (INSERT, UPDATE, DELETE)

- exclusive lock이 해제될 때까지, 다른 트랜잭션은 읽기 작업을 위해 shared lock이나 쓰기 작업을 위해 exclusive lock을 걸 수 없음

 

3.3. 설정 범위

3.3.1. 행

- 1개의 행을 기준으로 락 설정

- DML에 대한 락으로 가장 일반적인 범위

 

3.3.2. 페이지

- 파일의 일부인 페이지 단위러, 일반적으로 여러 행을 포함함

- 일반적으로 사용되지는 않음

 

3.3.3. 테이블

- 테이블 기준으로 락 설정

- DDL 구문과 함께 사용됨

 

3.3.4. 데이터베이스

- 일반적으로 사용되지는 않으며, DB 소프트웨어 버전 업데이트 등에 사용됨

 

 

참고자료

 

[DB] 트랜잭션 격리수준 (Isolation Level) 에 대해 차근차근 이해해보기

1. 개요 올해 6월부터 코로나 위기 단계가 하향 조정됨에 따라 7일 격리였던 격리 수준이 5일로 완화되었다. :) 어떤 단계에 따라 격리 수준 변경되고 있는데 우리가 사용하는 DB, 트랜잭션에도 격

tlatmsrud.tistory.com

 

트랜잭션의 격리 수준(isolation Level)이란?

 

nesoy.github.io

 

[MySQL] - 트랜잭션의 격리 수준(Isolation level)

📎 글또 6기 포스팅 1. 미치도록 더웠던 7월의 회고 2. 사용자가 게시물을 작성할 때의 트랜잭션 처리 3. Spring AOP - (1) 프록시 패턴, 데코레이터 패턴 4. [MySQL] - 트랜잭션의 격리 수준(Isolation level) 5

zzang9ha.tistory.com

 

Lock의 종류 (Shared Lock, Exclusive Lock, Record Lock, Gap Lock, Next-key Lock)

Lock의 종류 (Shared Lock, Exclusive Lock, Record Lock, Gap Lock, Next-key Lock)

jaeseongdev.github.io