데이터베이스

트랜잭션의 ACID 속성 중 격리성(Isolation)이 보장되지 않을 때 발생할 수 있는 문제점

00z11 2025. 3. 10. 09:12
트랜잭션의 ACID 속성 중 격리성(Isolation)에 대해서 간단하게 설명하고, 보장되지 않았을 때 발생할 수 있는 문제점과 이를 해결하기 위한 트랜잭션 격리 수준들을 제시합니다.

 

 


 

트랜잭션과 트랜잭션의 속성, 그리고 격리성(Isolation)

트랜잭션은 데이터베이스에서 여러 작업을 하나의 단위로 묶어 처리하는 개념입니다. 트랜잭션의 속성 ACID는 원자성(Atomicity), 일관성(Consistency), 격리성(Isolation), 지속성(Durability)을 의미하고, 이 속성을 지키는 것은 트랜잭션의 신뢰성을 높입니다.

그중 격리성(Isolation)은 동시에 실행되는 트랜잭션이 서로 간섭하지 않도록 보장하는 것으로 트랜잭션이 독립적으로 실행되도록 해 데이터의 일관성을 유지하도록 합니다.

 



ACID 속성 중 격리성이 보장되지 않았을 때의 문제점

트랜잭션에서 격리성이 보장되지 않는다는 건, 동시에 실행되는 트랜잭션이 서로 간섭할 수 있게 된다는 것입니다. 실행되는 트랜잭션이 서로에게 간섭할 때 다음과 같은 문제 세 가지가 발생합니다.

 

1. Dirty Read
한 트랜잭션이 아직 커밋되지 않은 다른 트랜잭션의 변경사항(UPDATE) 을 읽게 되는 현상

-- 트랜잭션 A
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE iD = 1; 
-- A COMMIT 하지 않음

-- 트랜잭션 B (아직 커밋되지 않은 트랜잭션 A의 변경사항인 데이터를 읽었다. 즉, Dirty Read 발생)
SELECT balance FROM accounts WHERE id = 1; -- -100 적용된 값을 조회한다

-- 트랜잭션 A 롤백
ROLLBACK; -- 트랜잭션 B가 읽은 값이 잘못된 데이터가 되어버린다.

 

 

 

2. Non-Repeatable Read
하나의 트랜잭션 내에서 동일한 데이터를 두 번 조회했을 때 그 값이 다르게 나타나는 현상

-- 트랜잭션 A (READ COMMITTED 격리 수준)
BEGIN;
SELECT balance FROM accounts WHERE id = 1; -- 결과 : 100

-- 트랜잭션 B
BEGIN;
UPDATE accounts SET balance = 200 WHERE id = 1;
COMMIT;

-- 트랜잭션 A (하나의 트랜잭션 내에서 동일한 데이터 두 번 조회했는데 값이 달라졌다. 즉, Non-repeatable Read 발생)
SELECT balance FROM accoutns WHERE id = 1; -- 결과 : 200
COMMIT;

 

 

3. Phantom Read
한 트랜잭션 내에서 동일한 쿼리를 실행했을 때 이전에 없던 레코드가 나타나거나 존재하던 레코드가 사라지는 현상(INSERT, DELETE)

-- 트랜잭션 A
BEGIN;
SELECT * FROM orders WHERE status = 'PENDING'; -- 결과 5개

-- 트랜잭션 B
BEGIN;
INSERT INTO orders (id, status) VALUES (101, 'PENDING');

-- 트랜잭션 A
SELECT * FROM orders WHERE status = 'PENDING'; -- 결과 6개
COMMIT;

 

 


 

트랜잭션 격리 수준과 문제점의 방지

  1. READ UNCOMMITTED
    다른 트랜잭션의 미완료 변경 사항을 읽을 수 있다.
  2. READ COMMITTED
    다른 트랜잭션이 COMMIT한 데이터만 읽을 수 있다. → Dirty Read 방지
  3. REPEATABLE READ
    트랜잭션 내에서 같은 데이터를 여러 번 조회해도 값이 변하지 않는다 → Dirty Read, Non-Repeatable Read 방지
  4. SERIALIZABLE
    모든 트랜잭션을 직렬화하여 실행한다.   Dirty Read, Non-Repeatable Read, Phantom Read 방지

 

READ UNCOMMITTED는 실무에서 거의 쓰지 않는 격리 수준으로, PostgreSQL은 READ UNCOMMITTED수준을 지원하지 않고 있습니다. SERIALIZABLE 또한 동시 처리량 급감, 데드락의 가능성이 매우 높아 잘 이용되지 않습니다.

대부분의 DBMS가 READ COMMITTED를 기본 격리 수준으로 채택하고 있습니다. Dirty Read를 방지하고, 성능적인 면에서 적잘하다 여기기 때문입니다.

 

SERIALIZABLE 격리 수준을 잘 이용하지 않는다면, Phantom Read 문제는 어떻게 될까요?

Phantom Read 는 범위 쿼리를 이용하면서, 동시에 다른 트랜잭션이 해당 범위에 데이터를 추가/삭제하는 경우에 발생하고, 모든 쿼리에서 발생하는 문제가 아니며, 실제 문제가 되지 않는 경우가 많습니다. Phantom Read가 문제가 될 수 있는 중요한 트랜잭션의 경우 애플리케이션 로직에서 이를 관리하거나 특정 트랜잭션에 대해서만 더 높은 격리 수준을 사용합니다.

 

 


트랜잭션과 ACID 속성 이해하기