[Oracle] 오라클 트랜잭션 수준 읽기 일관성, Transaction-Level Read Consistency
트랜잭션 수준 읽기 일관성
앞서 알아보았던 문장수준 읽기 일관성이 쿼리 시작 시점을 기준으로 삼았다면 트랜잭션 수준 읽기 일관성은 트랜잭션이 시작된 시점을 기준으로 일관성 있게 데이터를 읽어들이는 것을 말한다.
※ 오라클은 완벽한 문장수준의 읽기 일관성을 보장하지만, 트랜잭션에 대해서는 기본적으로 보장하지 않는다.
트랜잭션 고립화 수준 (Transaction Isolation Level)
- Level 0 (Read Uncommitted): Dirty Read, Non-Repeatable Read, Phantom Read 발생
* 오라클은 이 레벨을 지원하지 않음
- Level 1 (Read Committed): 거의 모든 DBMS의 Default, Non-Repeatable Read, Phantom Read 발생
- Level 2 (Repeatable Read): 선행 트랜잭션이 읽은 데이터는 트랜잭션이 종료될 때까지 후행 트랜잭션이 갱신 및 삭제 불가, Phantom Read 발생, Oracle의 for update
- Level 3 (Serializable Read): 선행 트랜잭션이 읽은 데이터는 트랜잭션이 종료될 때까지 후행 트랜잭션이 갱신, 삭제, 삽입 불가, 완벽한 읽기 일관성 모드를 제공
dirty read.. 더러운 것을 읽는다?
non-repeatable read.. 반복될 리 없는 것을 읽는다?
phantom read.. 유령을 읽는다???
(1) Dirty Read (= Uncommitted Dependency)
: 커밋되지 않은 데이터를 읽음으로써 발생하는 현상
TX1 |
|
TX2 |
| t1 | UPDATE 계좌 SET 잔고 = 잔고 + 10000 WHERE 계좌번호 = '123456'; |
SELECT SUM(잔고) FROM 계좌; | t2 | |
| t3 | ROLLBACK; |
☞ TX1의 최종 결과값이 비일관성 상태에 놓이게 됨
(2) Non-Repeatable Read (= Inconsistent Analysis) : SELECT 중에 UPDATE나 DELETE를 허용함으로써 발생하는 현상
TX1 |
|
TX2 |
SELECT 당월주문금액 into :amt FROM 고객 WHERE 고객번호 = 123; |
t1 |
|
|
t2 |
UPDATE 고객 SET 당월주문금액 = 60000, 등급 = 'A' WHERE 고객번호 = 123; |
| t3 | COMMIT; |
IF :amt >= 50000 THEN UPDATE 고객 SET 등급 = 'A' WHERE 고객번호 = 123; ELSE UPDATE 고객 SET 등급 = 'B' WHERE 고객번호 = 123; END IF; | t4 |
|
COMMIT; | t5 |
☞ t1 시점에 123번 고객의 당월주문금액이 40,000원이었다고 가정하면 최종적으로 당월주문금액 = 60,000 / 등급 = 'B'가 되는 Lost Update 발생 (SELECT .. FOR UPDATE를 통해 방지 가능)
(3) Phandom Read
: SELECT 중에 INSERT를 허용함으로써 발생하는 현상
TX1 |
|
TX2 |
INSERT INTO 지역별고객 SELECT 지역, COUNT(*) FROM 고객 GROUP BY 지역; | t1 |
|
|
t2 |
INSERT INFO 고객 (고객번호, 이름, 지역, 연령대, ...) VALUES (:a, :b, :c, :d, ...); |
| t3 | COMMIT; |
INSERT INTO 연령대별고객 SELECT 연령대, COUNT(*) FROM 고객 GROUP BY 연령대; | t4 |
|
COMMIT; | t5 |
☞ 지역별고객과 연령대별고객의 총고객수가 일치하지 않는 현상 발생 (트랜잭션 고립화 수준을 레벨3로 올림으로써 방지 가능)
set transaction isolation level serializable;
→ TX1의 모든 쿼리를 t1시점(트랜잭션 시작 시점)에 존재했던 고객만을 대상으로 수행
※ 오라클은 트랜잭션 고립화 수준을 높이더라도 Lock을 사용하지 않으므로 동시성이 저하되지는 않는다.
(오라클은 for update절을 사용하지 않는 한 절대 select문에 Lock을 사용하지 않는다.)
문장 수준(쿼리 단위)과 트랜잭션 수준(트랜잭션 단위)을 혼동하지 말자!!