본문 바로가기

CS

트랜잭션 고립수준

트랜잭션 격리 수준은 여러 트랜잭션이 동시에 수행될 때 서로 간섭하지 않도록 보장하는 정도를 의미합니다. 격리 수준이 높을수록 데이터 정합성은 보장되지만 성능은 저하되며, 낮을수록 성능은 좋지만 일관성 문제가 발생할 수 있습니다.

 


트랜잭션 격리 수준에 따른 문제

 


Dirty Read (더티 리드) :


다른 트랜잭션이 아직 커밋하지 않은 데이터를 읽는 문제입니다. 이후 "롤백"될 경우 읽은 데이터가 무효가 되어 데이터 일관성이 깨질 수 있습니다. 즉, Write 작업이 이루어지고 있는 트랜잭션에 접근해서 발생한 문제

 

READ UNCOMMITTED에서만 발생 가능

 

 

 


 

Non-Repeatable Read (반복 불가능한 읽기) :


하나의 트랜잭션에서 같은 데이터를 두 번 읽었을 때 값이 바뀌는 문제입니다. 두 읽기 사이에 다른 트랜잭션이 해당 데이터를 변경했을 가능성이 있습니다.

 

예를 들면 A 트랜잭션이 어떤 상품의 재고 수량을 조회했더니 10개인데 그 사이 B 트랜잭션이 그 상품의 재고를 8개로 바꿨고, 커밋한 경우 A 트랜잭션이 다시 같은 상품의 재고를 조회했더니 8개가 나왔을 때가 같은 데이터를 두 번 읽었는데 값이 달라진 상황입니다. 즉 같은 행을 두 번 읽었는데 값이 바뀐 것입니다.

 

팬텀 리드와의 차이점은 반복 가능하지 않은 조회는 행 값이 달라질 수 있는데, 팬텀 리드는 다른 행이 선택될 수도 있다는 것을 의미합니다.

 

READ COMMITTED 부터 가능

 


Phantom Read (팬텀 리드) :


팬텀 리드는 한 트랜잭션에서 동일한 쿼리를 보냈을 때 해당 조회 결과가 다른 경우를 의미합니다. 이름 그대로 없던 row가 두 번째 쿼리에서 나타나는 현상입니다. (즉, INSERT 쿼리에서 발생)

 

예를 들면 A 트랜잭션이 "재고가 5개 이상인 상품 목록"을 조회했더니 상품 A, B가 나왔지만 그 사이 B 트랜잭션이 조건에 맞는 새로운 상품 C를 추가하고 커밋을 하게 되면

 

A 트랜잭션이 다시 같은 조건으로 목록을 조회했더니 상품 A, B, C가 나오게 됩니다 정리하면 조회 조건은 같았지만, 처음엔 없던 "새로운 행"이 생겨난 것입니다.

 

REPEATABLE READ 부터 가능

 

 

READ UNCOMMITTED 커밋되지 않은 데이터도 조회 가능 Dirty Read, Non-Repeatable Read, Phantom Read
READ COMMITTED 커밋된 데이터만 조회 가능 Non-Repeatable Read, Phantom Read
REPEATABLE READ 같은 쿼리는 항상 같은 결과를 반환
(단, 새 행 삽입은 허용됨)
Phantom Read
SERIALIZABLE 가장 높은 격리 수준, 전체 테이블 레벨 잠금 없음 (모든 문제 방지)

 


트랜잭션 고립 수준 별 정리

 

 

 

READ UNCOMMITTED 

 

커밋이 되지 않은 트랜잭션의 데이터 변경 내용을 다른 트랜잭션이 조회하는 것을 허용하는 격리 수준입니다. 데이터 부정합 문제가 발생할 확률이 높지만, 성능은 가장 빠르며 데이터를 어림잡아 집계하는 등의 연산에서 사용하면 좋습니다.

 

 


READ COMMITTED

 

커밋이 완료된 트랜잭션의 변경사항만 다른 트랜잭션에서 조회할 수 있도록 허용하는 격리 수준입니다. 즉, 특정 트랜잭션이 이루어지는 동안 다른 트랜잭션은 해당 데이터에 접근할 수 없습니다. 가장 많이 사용되는 격리 수준입니다.

 

특정 트랜잭션에서 데이터가 변경되었으나, 아직 커밋되지 않은 상태라면 다른 트랜잭션에서는 해당 데이터에 접근했을 때 트랜잭션 시작 전 데이터를 읽어오며 커밋이 된 이후에서야 변경된 데이터 값을 읽어올 수 있습니다.

 


REPEATABLE READ

 

특정 행을 조회시 항상 같은 데이터를 응답하는 것을 보장하는 격리 수준입니다. 하지만, SERIALIZABLE과 다르게 행이 추가되는 것을 막지는 않습니다. 이로 인해 팬텀 리드 현상이 발생할 수 있다. MySQL의 InnoDB엔진의 기본 격리 수준이 REPEATABLE READ입니다.

 


SERIALIZABLE 

 

특정 트랜잭션이 사용중인 테이블의 모든 행을 다른 트랜잭션이 접근할 수 없도록 잠그는 것입니다. 가장 높은 데이터 정합성을 갖으나, 성능은 가장 떨어지며 이 격리 수준에서는 단순한 SELECT 쿼리가 실행되더라도, 데이터베이스 락이 걸려 다른 트랜잭션에서 데이터에 접근할 수 없게 됩니다.