트랜잭션 격리수준
동시에 여러 트랜잭션이 처리될 때, 트랜잭션끼리 얼마나 격리되어 있는 지 수준을 말한다.
격리성을 강화시키면 다른 트랜잭션이 끼어들지 못하게 보장할 수 있고, 약화시키면 다른 트랜잭션도 중간에 끼어들 수 있다. 준수한 처리 속도를 위해서는 트랜잭션의 완전한 격리가 아닌 완화된 수준의 격리가 필요하다.
이처럼 속도와 데이터 정확성에 대한 트레이드 오프를 고려하여 트랜잭션의 격리성 수준을 나눈 것이 바로 트랜잭션의 격리수준이다.
트랜잭션 ACID
1. Atomicity 원자성
한 트랜잭션의 연산은 모두 성공하거나, 모두 실패해야 한다. 예를 들어, 돈을 이체할 때 돈을 빼오는 작업만 성공하고, 돈을 넣는 작업은 실패하면 안된다.
2. Consistency 일관성
트랜잭션 처리 후에도 데이터의 상태는 일관되어야 한다.
3. Isolation 격리성
트랜잭션 수행 시 다른 트랜잭션의 연산이 끼어들지 못하도록 보장한다.
4. Durabilitiy 지속성
성공적으로 수행된 트랜잭션은 영원히 반영되어야 한다. 중간에 DB 오류가 발생해도 다시 복구되어야 한다. 트랜잭션에 대한 로그가 반드시 남아야 한다.
UnCommitted Read (커밋되지 않은 읽기)
다른 트랜잭션에서 커밋되지 않은 데이터에 접근할 수 있게 해주는 격리 수준. 가장 저수준의 격리수준이며, 일반적으로 사용하지 않는다.
예) 10번 트랜잭션이 "111"이라는 데이터를 "222"로 UPDATE한 후 Commit하지 않았을 때,
13번 트랜잭션에서 접근하여 커밋되지 않은 데이터를 읽을 수 있다.
그런데 이 격리수준은, 만약 13번 트랜잭션이 "222"를 읽은 후, 10번 트랜잭션에서 "222" 업데이트가 문제가 발생하여 "111"로 롤백된다면 데이터 부정합을 발생시킬 수 있다.
커밋되지 않은 트랜잭션에 접근하여 부정합을 유발할 수 있는 데이터를 읽는 것을 더티읽기(Dirty Read)라고 한다.
Committed Read (커밋된 읽기)
다른 트랜잭션에서 커밋된 데이터로만 접근할 수 있게 하는 격리 수준이다. MySQL을 제외하고 대부분 이를 기본 격리수준으로 사용한다.
예) 10번 트랜잭션이 '111'이라는 데이터를 '222'로 UPDATE 한 후 Commit 하지 않았을 때, 13번 트랜잭션에서 이를 조회할 경우 UPDATE 전 데이터인 '111' 이라는 값이 조회된다. Dirty Read 현상은 발생하지 않는다.
어떻게 UPDATE 전 값을 조회한 걸까?
Undo 영역이란? 변경 전 데이터가 저장된 영역이고, Commit 하기 전 데이터를 읽어올 수 있는 이유는 Undo 영역에 있는 데이터를 읽어오기 때문이다.
Commited Read 수준에서는 Non Repeatable Read 현상이 발생한다. 이는 하나의 트랜잭션에서 동일한 SELECT 쿼리를 날렸을 때 다른 결과가 나타나는 것을 말한다.예) 13번 트랜잭션이 SELECT 쿼리를 두 번 날렸을 때, 10번 트랜잭션이 UPDATE 후 커밋하기 전, 후에 쿼리를 실행했기 때문에 실행 결과가 다르다.
Repeatable Read (반복 가능한 읽기)
Non Repeatable Read 문제를 해결하는 격리 수준으로, 자신보다 낮은 트랜잭션 번호를 갖는 트랜잭션에서 커밋한 데이터만 읽을 수 있는 격리 수준이다. 즉, 자신보다 나중에 실행된 트랜잭션은 읽지 못한다.예) 10번 트랜잭션은 10번보다 작은 트랜잭션에서 커밋한 데이터만 읽을 수 있다.-> 13번 트랜잭션에서 변경한 내용은 조회할 수 없다.
Serializable (직렬화 가능)
가장 엄격한 격리 수준으로, 트랜잭션을 순차적으로 진행시킨다.
여러 트랜잭션이 동일한 레코드에서 동시 접근할 수 없으므로, 어떠한 데이터 부정합 문제도 발생하지 않지만 트랜잭션이 순차적으로 처리되어야 하므로 동시 처리 성능이 매우 떨어진다.
요약
Read Committed는 데이터 부정합 문제가 지나치게 발생하고, Serializable은 동시성이 상당히 떨어지므로 Read Committed 또는 Repeatable Read를 사용하면 된다. 오라클에서는 Read Committed를 기본으로 사용하며, MySQL에서는 Repeatable Read를 사용한다.
Dirty Read | Non Repeatable Read | Phantom Read | |
Read Uncommitted | 발생 | 발생 | 발생 |
Read Committed | X | 발생 | 발생 |
Repeatable Read | X | X | 발생(MySQL은 거의 X) |
Serializable | X | X | X |
- Dirty Read: 커밋되지 않은 다른 트랜잭션의 데이터를 읽음.
- Non-Repeatable Read: 한 트랜잭션에서 같은 쿼리로 2번 이상 조회했을 때 그 결과가 다름. 보통 데이터의 수정/삭제 시 발생
- Phantom Read: 한 트랜잭션에서 같은 쿼리를 2번 이상 조회했을 때, 없던 결과가 조회되는 상황. 결과 레코드 수가 달라진다. 데이터 삽입이 발생했을 경우 발생
'Spring' 카테고리의 다른 글
[Spring] JPA hibernate의 ddl-auto 속성 (0) | 2024.05.06 |
---|---|
[Spring] @Profile로 활성 프로파일 지정하기 (0) | 2024.05.06 |
[Spring] Spring Security 동작 원리, 왜 사용하는 지 (0) | 2024.04.20 |
[Spring] Spring의 DI: 생성자 주입 vs 필드 주입 (0) | 2024.04.20 |
[Spring] DAO, DTO, VO 차이 (1) | 2023.10.26 |