트랜잭션 특징과 격리 수준 (Isolation Level)

    트랜잭션 특징

    트랜잭션은 원자성, 일관성, 지속성, 격리성을 보장한다.

    원자성(Atomicity)

    트랜잭션 내에서 실행한 작업들은 마치 하나의 작업인 것처럼 모두 성공 또는 실패해야 한다

    일관성(Consistency)

    모든 트랜잭션은 일관성 있는 데이터베이스 상태를 유지해야 한다

    트랜잭션이 진행되는 동안에 데이터베이스가 변경 되더라도 업데이트된 데이터베이스로 트랜잭션이 진행되는것이 아니라, 처음에 트랜잭션을 진행 하기 위해 참조한 데이터베이스로 진행된다.

    지속성(Durability)

    트랜잭션이 성공적으로 끝나면 그 결과가 영구적으로 반영되어야 한다.

    중간에 시스템에 문제가 발생해도 데이터베이스 로그 등을 사용해서 성공한 트랜잭션 내용을 복구할 수 있어야 한다.

    격리성(Isolation)

    동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않도록 격리한다.

    격리성은 동시성과 관련된 성능 이슈로 인해 격리 수준을 선택할 수 있다. -> 트랜잭션 격리 수준 (Isolation Level)

    트랜잭션 격리 수준

    • Read Uncommitted (커밋되지 않은 읽기)
    • Read Committed (커밋된 읽기)
    • Repeatable Read (반복 가능한 읽기)
    • Serializable (직렬화 가능)

    위에서 아래 순서대로 격리 수준이 높아진다.

    READ UNCOMMITTED

    각 트랜잭션의 변경 내용이 COMMIT이나 ROLLBACK 여부와 상관 없이 다른 트랜잭션에서 데이터를 읽을 수 있다.

     

    문제점: DIRTY READ

    1. 트랜잭션 A 에서 1번 계좌 잔고를 100만원에서 0원으로 변경하고 커밋하지 않음
    2. 트랜잭션 B 에서 1번 계좌 잔고를 조회 (0원)
    3. 트랜잭션 A 에서 문제가 발생해 롤백
    4. 트랜잭션 B 에서 1번 계좌 잔고가 0원이라고 생각하고 로직을 수행함

     

    위와 같은 식으로 Dirty Read가 발생하면 데이터 정합성에 심각한 문제가 발생

    READ COMMITTED

    커밋한 데이터만 다른 트랜잭션에서 조회할 수 있다. 따라서 Dirty Read가 발생하지 않는다.

    오라클 DBMS에서 기본으로 사용되는 격리 수준이다.

    1. 트랜잭션 B 에서 1번 계좌 잔고를 100만원에서 0원으로 변경
    2. 0원은 테이블에 즉시 기록되고, 이전 값인 100만원은 undo 영역으로 백업
    3. 트랜잭션 B가 커밋되기 전에 트랜잭션 A가 1번 계좌 잔고를 조회하면 테이블이 아닌 undo 영역에 백업된 레코드인 100만원이 조회됨
    4. 트랜잭션 B가 커밋된 후에 조회 시에는 undo 레코드가 아닌 변경된 값인 0원이 조회됨

     

    문제점: NON-REPEATABLE READ

    1. 트랜잭션 A 에서 1번 계좌 잔고를 조회 (100만원이 조회됨)
    2. 트랜잭션 B 에서 1번 계좌 잔고를 100만원에서 0원으로 변경하고 커밋
    3. 트랜잭션 A 에서 1번 계좌 잔고를 다시 조회하면 0원이 조회됨

     

    이는 하나의 트랜잭션내에서 똑같은 SELECT를 수행했을 경우 항상 같은 결과를 반환해야 한다는 REPEATABLE READ 정합성에 어긋나는 것이다. 

    READ COMMITTED 격리수준에서는 이처럼 반복해서 같은 데이터를 읽을 수 없는 상태인 NON-REPEATABLE READ를 허용한다.

    ※ 트랜잭션 내 (START TRANSACTION 명령으로 시작) 에서 실행되는 SELECT와 트랜잭션 없이 실행되는 SELECT는 엄연히 다름. 금전적인 작업 처리에서 같은 트랜잭션 내에서 같은 결과를 보장하는 것은 중요

     

    REPETABLE READ

    한 번 조회한 데이터를 반복해서 조회해도 같은 데이터가 조회된다.

    MySQL InnoDB 스토리지 엔진에서 기본적으로 사용되는 격리 수준이다.

     

    모든 InnoDB의 트랜잭션은 고유한 트랜잭션 번호를 가지며, undo 영역에 백업된 모든 레코드에도 트랜잭션 번호가 포함되어 있다.

    1. 트랜잭션 C가 1번 계좌 잔고를 100만원으로 설정(Transaction No.9)
    2. 트랜잭션 A에서 1번 계좌 잔고 조회 (Transaction No.10)
    3. 트랜잭션 B 에서 1번 계좌 잔고를 100만원에서 0원으로 변경 (Transaction No.11)

    4. 트랜잭션 A는 트랜잭션 번호가 10이므로 10보다 작은 트랜잭션 번호에서 변경한 것만 보이므로 항상 100만 원만 조회가 된다.

     

    문제점: PHANTOM READ

    1. 트랜잭션 A 에서 전체 계좌를 조회했을 때 3개가 조회됨
    2. 트랜잭션 B 에서 4번 계좌 잔고를 추가
    3. 트랜잭션 A 에서 다시 전체 계좌를 조회했을 때 4개가 조회됨

     

    이처럼 반복조회 시 결과 집합이 달라지는 것을 PHANTOM READ라고 한다.

     

    InnoDB 스토리지 엔진은 갭 락과 넥스트 키 락을 사용하여 PHANTOM READ을 해결한다.

     

    SERIALIZABLE

    가장 엄격한 격리 수준

    PHANTOM READ가 발생하지 않지만 동시성 처리 성능이 급격히 떨어질 수 있다.

     

    728x90

    댓글