트랜잭션 격리 수준(Isolation Level)이란?
트랜잭션의 격리 수준은 여러 트랜잭션이 혼재되어 있는 상태에서, 하나의 트랜잭션이 다른 트랜잭션의 데이터에 접근 할 수 있는 '정도'를 의미한다.
트랜잭션 격리 수준은 4단계로 나뉘어 진다.
0 - Read Uncommitted
1 - Read Committed
2 - Repeatable Read
3 - Serializable
격리 수준이 높아질 수록 트랜잭션의 고립 강도가 높아지는 반면, 성능저하도 야기된다.
일반적인 서비스에서는 Read Committed 혹은 Repeatable Read 수준을 사용하며, 서비스의 요구사항에 따라 적절한 격리 수준을 정해 사용해야 한다.
여러 트랜잭션이 존재하는 상황에서 트랜잭션들의 경합으로 발생하는 문제는 격리수준별 다음 표와 같다.
격리 수준 | Dirty Read | Non-Repeatable Read | Phantom Read |
0 - Read Uncommitted | O | O | O |
1 - Read Committed | X | O | O |
2 - Repeatable Read | X | X | O |
3 - Serializable | X | X | X |
트랜잭션의 격리수준
0-Read Uncommitted
레벨 0 Read Unccommitted 레벨은 트랜잭션이 다른 트랜잭션의 commit 되지 않은 데이터에 대한 접근이 허용되는 레벨이다.
해당 레벨에서는 ACID 원칙중 Atomicity와 Isolation 원칙을 위배하게 된다.
좀 더 자세히 내용을 살펴보면, A 트랜잭션과 B 트랜잭션이 존재할때 두 트랜잭션의 동작은 Dirty Read 이슈를 발생시킨다.
A 트랜잭션 : A고객 통장 잔고 10,000원 -> 12,000원 수정 (Commit 전)
B 트랜잭션 : A고객 통장 잔고 조회 (12,000원 조회)
A 트랜잭션 : 로직 이슈로 인하여 A 고객의 통장 잔고 정보 Rollback
B 트랜잭션 : A트랜잭션의 Rollback과 상관없이 12,000원으로 조회한 A 고객의 통장 잔고를 토대로 로직 진행
트랜잭션간의 독립된 동작을 보장해야하는 Isolation원칙과 트랜잭션은 전체가 성공하거나 전체가 실패해야 한다는 Atomicity 원칙을 위배하게 된다.
언뜻 보기에는 B 트랜잭션은 독립적으로 수행되었기때문에 Atomicity 원칙을 준수한 것처럼 보일 수 있으나, 문제는 B 트랜잭션이 A 트랜잭션의 데이터를 읽고, 이를 기반으로 작업을 수행했기 때문이다.
B 트랜잭션의 Atomicity 원칙을 준수하기 위해서는 A 트랜잭션이 롤백되는 시점에 B 트랜잭션 또한 롤백되어야 한다.
Dirty Read는 아직 Commit되지 않은 트랜잭션의 변경사항을 다른 Transaction에서 읽을 수 있는 이슈를 의미한다.
Dirty Read 문제는 Read Committed 레벨에서 해소된다.
1-Read Committed
레벨 1 Read Committed 레벨은 다른 트랜잭션의 데이터를 조회할 경우 Commit된 데이터만 읽을 수 있도록 허용하는 레벨이다.
즉 A 트랜잭션이 변경후 Commit 하지 않은 상태에서 B 트랜잭션이 A 트랜잭션의 데이터를 조회할 경우 A 트랜잭션이 수정하기 이전의 데이터를 조회하게 된다.
레벨 0에서 발생하던 Dirty Read는 현재 수준의 레벨부터는 더이상 발생하지 않으며, 대부분의 DBMS에서는 현재 레벨의 격리 수준을 Default로 설정하고 있다.
그럼 어떻게 B 트랜잭션에서는 A 트랜잭션의 Commit 이전 데이터를 조회할 수 있을까?
이 부분은 DBMS별로 약간의 차이가 있으나, DBMS에서는 트랜잭션이 이루어지기전 UNDO 영역에 데이터를 임시로 저장해두고, 이곳을 조회하도록 기능을 제공한다.
Read Committed에서는 Dirty Read가 없어졌으니 완벽한 '격리 수준'이라고 볼 수 있을까?
Read Committed에서는 Non-Repetable Read 부정합 문제가 발생할 수 있다.
아래 예시를 통해 살펴보자.
A 트랜잭션 : '고윤정' 이름 고객정보 등록 (Commit 이전이므로 Undo 영역에는 데이터가 없음)
B 트랜잭션 : '고윤정' 고객 정보 조회 -> 조회결과 없음
A 트랜잭션 : Commit
B 트랜잭션 : '고윤정' 고객 정보 조회 -> 고객 정보 결과 반환
B 트랜잭션 입장에서는 분명 동일한 하나의 트랜잭션임에도 내부에서 반복적으로 조회할 때 조회 결과 값이 다른 이슈가 발생하였다.
즉 B 트랜잭션 입장에서 '고윤정' 이라는 고객정보에 대한 정합성이 부정합하게 나타나게 되었고 이런 이슈를 Non-Repetable Read 이슈라고 한다.
Non-Repeatable Read 이슈는 Repetable Read 레벨에서 해소된다.
2-Repeatable Read
Repeatable Read는 트랜잭션 범위 내에서 조회한 내용이 항상 동일함을 보장하는 트랜잭션 격리 수준이다.
3-Serializable
Serializable은 모든 작업을 하나의 트랜잭션에서 처리하는 것과 같이 동작하는 가장 높은 트랜잭션 격리 수준이다.
따라서 Phantom Read 문제가 발생하지 않으나, Deadlock에 걸릴 가능성이 존재함과 더불어 동시성 처리 성능이 저하되기 때문에 신중하게 사용해야 한다.
'Database' 카테고리의 다른 글
[Database] 비관적 락(Passimistic Lock)과 낙관적 락(Optimistic Lock) (0) | 2025.02.07 |
---|---|
[Database] 트랜잭션(Transaction)과 ACID 개념 (1) | 2024.04.13 |
[Database] Ms-SQL DeadLock 이슈 처리 (0) | 2023.08.22 |