DB

트랜잭션 격리 수준(isolation level)

gracelove91 2020. 7. 14. 08:19

개요

본 포스팅의 DB환경은 MySQL 5.7.30 입니다. 테스트를 원하신다면 AUTO_COMMIT을 false로 하고 진행해주세요.

트랜잭션 격리 수준이란 ?

  • 동시에 여러 트랜잭션이 처리될 때, 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있도록 허용할 지 말지를 결정한다.

트랜잭션 격리 수준의 종류

  • READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE 등으로 나뉜다.

왜 트랜잭션 격리 수준을 알아야 하는 가?

  • 동시성 문제가 있다. 데이터 부정합 문제점이 있는데, 이는 트랜잭션 격리 수준에 따라 달라진다. 아래 그림은 트랜잭션 격리 수준에 따른 데이터 부정합 표이다. 각각의 데이터 부정합의 대한 설명은 아래에서 다시 다룰 것이다.

테스트를 위한 준비

  • AUTO_COMMIT을 false로 설정한다.
  • 아래와 같이 간단한 테이블을 만들고, 데이터를 집어넣자.
create table account (
    account_id int AUTO_INCREMENT,
    login_name varchar(255) not null,
    primary key(account_id)
)charset='utf8';

insert into account(login_name)
values ('eunmo');
  • 트랜잭션 격리 수준을 설정하는 SQL과 확인하는 SQL은 다음과 같다.

    • ex ) READ UNCOMMITTED 로 설정하고 싶을 때.

      SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
      
      SHOW VARIABLES LIKE 'TX_ISOLATION';
      
    • 결과

주의!!! 테스트 할 때는 서로 다른 세션에서 수행해야한다! 현재 세션 확인하는 법 : select connection_id();

트랜잭션 격리 수준의 종류

READ UNCOMMITED

  • 각 트랜잭션에서의 변경 내용이 COMMIT이나 ROLLBACK 여부에 상관없이 다른 트랜잭션에서 보여진다. 실험을 해보자.

    1번 세션

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    
    UPDATE ACCOUNT
    SET LOGIN_NAME = 'GRACE LOVE'
    WHERE ACCOUNT_ID = 1;
    

    2번 세션

    begin;
    select * from account;
    

    결과

    문제

    • 결론적으로 1번 세션 트랜잭션에서 작업을 아직 완료하지 않았는데도 다른 트랜잭션이 이를 볼 수 있다.
    • 이렇게 어떤 트랜잭션에서 처리한 작업이 완료되지 않았는데도 다른 트랜잭션이 볼 수 있게 되는 현상을 Dirty read라고 한다.

    결론

    • 1번 세션에서 UPDATE 를 하고 COMMIT 하지 않았는데도 2번 세션에서는 UPDATE한 'GRACE LOVE' 가 보인다.
    • READ UNCOMMITED는 이런 데이터 부정합을 초래하므로 권장하지 않는다. 최소한 READ COMMITED 를 사용하자.

READ COMMITED

  • 어떤 트랜잭션에서 데이터를 변경했더라도 COMMIT이 완료된 데이터만 다른 트랜잭션에서 볼 수 있다.

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

    1번 세션

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
    
    UPDATE ACCOUNT
    SET LOGIN_NAME = 'GRACE LOVE'
    WHERE ACCOUNT_ID = 1;

    2번 세션

    begin;
    select * from account;
    

    결과 - COMMIT 실행 이전

    결과2 - COMMIT 실행 이후

    • 설명한 대로 COMMIT을 하지 않았기 때문에 UPDATE 한 값인 'GRACE LOVE' 가 다른 트랜잭션에선 보이지 않는다.
    • 1번 세션에서 COMMIT을 수행한 뒤 다시 2번 세션에서 조회해보자.

    문제

    • Dirty Read와 같은 부정합 문제는 발생하지 않는다.
    • 하지만 Non-Repeatable Read문제가 발생한다.
    • Non-Repeatable Read란 하나의 트랜잭션 내에서 똑같은 SELECT 쿼리를 실행했을 때 항상 같은 결과를 가져와야하는 Repeatable Read 정합성에 어긋나는 것이다.

    결론

    • SELECT 쿼리 결과는 ACCOUNT 테이블에서 가져온 것이 아니라, UNDO 영역에 백업된 컬럼 값을 가져오는 것이다.

REPEATABLE READ

  • InnoDB 스토리지 엔진의 기본 전략이다.
  • READ COMMITTED 와의 차이점은 UNDO 영역에 백업된 레코드의 여러 버전 가운데 몇 번째 이전 버전까지 찾아 들어가냐가 다르다.
  • 1번 세션이 UPDATE후 COMMIT 해도 다른 트랜잭션은 여전히 UNDO 영역을 바라보고있다.
  • PHANTOM READ가 발생할 수 있다고 하는데 InnoDB에선 발생하지 않는다 한다. 실제로 InnoDB 엔진에서 재현해보려했으나 실패했다.
    • PHANTOM READ ? 다른 트랜잭션에서 수행한 변경작업에 의해 레코드가 보였다 안보였다 하는 현상을 말한다.

SERIALIZABLE

  • 가장 엄격한 격리수준. 그만큼 동시처리성능도 가장 떨어진다. 어차피 InnoDB는 PHANTOM READ가 발생하지 않기 때문에 굳이 쓸 필요가 없다.

레퍼런스

Real MySQL - 이성욱 지음. 책 구매 링크 : http://www.yes24.com/Product/Goods/6960931