ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [DB] 트랜잭션 격리수준 (Isolation Level)
    database/DB Concept 2022. 1. 31. 19:00

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


     

     

    동시성(Concurrency) 문제


    실제 서비스에서는 많은 사용자가 동시 다발적으로 서버에 요청을 하게 되고 서버는 데이터베이스에 다시 트랜잭션을 요청하게 됩니다. 모든 요청을 순서대로 처리하게 된다면 동시성(Concurrency) 문제가 생길 것입니다. 반대로 동시성을 보장하기 위해 모든 요청을 동시에 처리하려고 한다면 데이터의 값이 맞지 않는 일관성(Consistency) 문제가 생기게 됩니다.

     

     

     

    Isolation 이 낮다면 발생하는 문제들


    아래와 같은 회원 테이블이 있습니다. 이 테이블에 대한 트랜잭션이 동시에 일어나면 어떤 문제가 있을까

    회원 테이블
    이름 VARCHAR 장장스
    잔액 BIGINT 10000
    등급 VARCHAR BRONZE
    지역 VARCHAR 서울

     

    1) Dirty Read가 발생하는 경우

    아직 커밋되지 않은 데이터를 수정하는 도중 다른 트랜잭션에서 READ를 허용할 때 발생한다.

    트랜잭션 (T1) 트랜잭션 (T2)
    SELECT 잔액 FROM 회원 테이블
    WHERE 이름=장장스;
     
    UPDATE 회원 테이블 SET 잔액 = 9000
    WHERE 이름=장장스;
     
      SELECT 잔액 FROM 회원 테이블
    WHERE 이름=장장스;
    ROLLBACK;  

    트랜잭션(T1)이 회원 테이블에 접근하여 잔액을 10,000에서 9,000으로 변경 했습니다. COMMIT을 하지 않았습니다. 그런데 다른 트랜잭션(T2)이 회원 테이블에 접근하여 잔액을 READ해 보니 9,000원 입니다. 트랜잭션(T1)은 수정사항을 COMMIT 하지 않고 ROLLBACK 했습니다. 따라서 장장스의 잔액은 10,000원입니다. 그러나 트랜잭션(T2) 가 조회한 잔액은 9,000원으로 데이터가 다릅니다.

     

    2) Non-Repeatable Read가 발생하는 경우

    트랜잭션 내에서 같은 내용의 쿼리가 반복해서 수행할 때,  다른 트랜잭션이 값을 수정 또는 삭제함으로써 두 쿼리가 상이하게 나타나는 비 일관성(Consistency)이 발생한다

    트랜잭션 (T1) 트랜잭션 (T2)
    SELECT 잔액 FROM 회원 테이블;  
      UPDATE 회원 테이블 SET 잔액 = 5000
    WHERE 이름=장장스;
      COMMIT;
    IF 잔액 >= 10000
    UPDATE 회원 테이블 SET 등급 = SILVER
     
    COMMIT;  

    트랜잭션(T1)이 회원 테이블을 READ하고 있었습니다. 이때 트랜잭션(T2)가 데이터에 접근하여 값을 변경(삭제) 후 COMMIT을 했습니다. 트랜잭션(T1)이 다시 해당 데이터를  READ 하려 하는데 데이터가 변경(삭제) 되어 찾을 수가 없습니다.

     

    3) Phantom Read

    하나의 트랜잭션에서 일정범위의 레코드를 두 번 이상 읽을 때, 첫 번재 쿼리에서 없던 유령 레코드가 두번째 쿼리에서 나타나는 현상을 발생한다.

    트랜잭션 (T1) 트랜잭션 (T2)
    INSERT INTO 지역별 회원 테이블
        SELECT 지역, COUNT(*)
        FROM 회원 테이블 GROUP BY 지역;
     
      INSERT INTO 회원 테이블(이름, 잔액, 등급, 지역)
    VALUES('강건마', 500, 'BRONZE', '부산');
      COMMIT;
    INSERT INTO 등급별 회원 테이블
        SELECT 등급, COUNT(*)
        FROM 회원 테이블 GROUP BY 등급;
     
    COMMIT;  

     

    트랜잭션(T1)이 지역별, 등급별 회원을 집계하는 도중 트랜잭션(T2)가 새로운 회원을 등록하게 되었다.

    그 결과 지역별 회원 테이블과 등급별 회원 테이블의 총 인원수가 불일치하게 된다.

     

     

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


    이처럼 동일성(Concurrency)을 높이다 보면 일관성(Consistency) 문제가 발생하는 것을 알 수 있습니다. 이러한 문제 해결을 위한 방법으로 트랜잭션 격리수준을 설정할 수 있습니다.

     

    [Level 0] READ UNCOMMITTED

    • 트랜잭션에서 처리 중인, 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용
    • Dirty Read, Non-Repeatable Read, Phantom Read 가 발생합니다.
    • 참고로 Oracle의 경우 Read Uncommitted 레벨은 지원하지 않습니다.

     

    [Level 1] READ COMMITTED

    • 트랜잭션이 커밋되어 확정된 데이터만 읽는 것을 허용합니다.
    • DB2, SQL Server, Sybase같이 대부분의 DBMS가 기본모드로 채택하고 있습니다. READ 경우 '공유 Lock'을 이용해서 구현합니다. 하나의 레코드를 읽을 때 Lock을 설정하고 해당 레코드를 빠져 나가는 순간 Lock 해제합니다.
    • Dirty Read 를 방지할 수 있으나 Non-Repeatable Read, Phantom Read는 발생합니다.
    • Oracle database 11g의 기본 Isolation level 입니다. Oracle database는 원본 레코드를 사용하지 않고 읽기 전용 데이터 셋을 (read-consistent set of data)생성하여 사용합니다. 사용자가 데이터를 수정할 때면 COMMIT 이전까지의 변경사항을 "Undo Segments" 기록하는 방법으로 일관성을 보장합니다.

     

    [Level 2] REPEATABLE READ

    • 선행 트랜잭션이 읽은 데이터는 트랜잭션이 종료될 때가지 다른 트랜잭션이 갱신하거나 삭제하지 못하도록 하여 같은 데이터를 두 번 쿼리했을 때 일관성 있는 결과를 리턴하도록 합니다.
    • Dirty Read, Non-Repeatable Read를 방지할 수 있으나 Phantom Read는 발생합니다.
    • InnoDB 스토리 엔진을 사용하는MySQL, MariaDB의 기본 Isolation level 입니다. 

     

    [Level 3] SERIALIZABLE

    • 선행 트랜잭션이 읽은 데이터를 다른 트랜잭션이 수정/삭제하지 못할 뿐만 아니라 중간에 새로운 레코드를 산입하지 못하도록 막아 완벽하게 읽기 일관성 모드를 제공합니다.

     

     

    Post


    References



    잘못된 코드나 내용이 있다면 댓글을 남겨주세요. 즉시 수정하도록 하겠습니다! :)

     

     

    댓글