[ CS / DataBase ] Transaction isolation level

황승환·2022년 5월 9일
0

CS

목록 보기
45/60

Transaction isolation level

트랜잭션 격리 수준이란, 여러 개의 트랜잭션이 동시에 처리될 때에 트랜잭션 간 고립의 정도를 나타내는 것이다.

격리 수준은 다음과 같이 4가지로 나눠진다.

  • READ UNCOMMITTED
  • READ COMMITTED
  • REPEATABLE READ
  • SERIALIZABLE

READ UNCOMMITTED

READ UNCOMMITTED 격리 수준에서는 커밋이나 롤백에 상관 없이 다른 트랜잭션에서 변경 사항을 읽을 수 있다.

  • A 트랜잭션에서 회사의 주소를 경기도에서 서울로 변경하고, 커밋을 하지 않았다.
  • B 트랜잭션에서 회사의 주소를 조회하니 서울로 조회가 된다. (더티 리드)
  • A 트랜잭션에 문제가 발생하여 롤백을 한다.
  • B 트랜잭션은 여전히 회사의 주소가 서울이라고 생각하고 작업을 수행한다.

데이터 정합성이 매우 떨어지기 때문에 RDBMS 표준에서는 격리 수준으로 인정하지 않는다.

READ COMMITTED

READ COMMITTED 격리 수준에서는 어떤 트랜잭션의 변경 사항이 커밋 되어야만 다른 트랜잭션에서 읽을 수 있다. ORACLE DBMS에서 디폴트로 사용하는 격리 수준으로, 온라인 서비스에서 가장 많이 사용된다.

여기서는 회사의 주소를 A 트랜잭션이 커밋하기 전까지 경기도로 읽게 되기 때문에 더티 리드와 같은 문제가 발생하지 않는다.

그러나 이 경우도 정합성 문제가 완전히 해결된 것은 아니다.

  • B 트랜잭션이 회사의 주소를 조회하면 경기도로 조회된다.
  • A 트랜잭션에서 회사의 주소를 서울로 변경하고 커밋한다.
  • B 트랜잭션이 회사의 주소를 조회하면 서울로 조회된다.

이 경우에는 NON-REPEATABLE READ 부정합 문제가 발생할 수 있다. 이는 하나의 트랜잭션 내에서 똑같은 SELECT문을 수행하면 똑같은 결과가 반환되어야 한다는 REPEATABLE READ 정합성에 어긋나는 경우이다.

일반적인 웹 어플리케이션에서는 문제가 없지만, 금전적인 처리와 관련있는 작업의 경우에는 문제가 발생할 수 있다.

REPEATABLE READ

REPEATABLE READ는 하나의 트랜잭션 내에서 똑같은 SELECT문을 수행하면 똑같은 결과가 반환되어야 한다는 정합성으로, 이를 보장하기 위해 트랜잭션이 시작되기 전에 커밋된 내용에 대해서만 조회할 수 있는 격리 수준이다. MySQL DBMS에서 디폴트로 사용되는 격리 수준으로, NON-REPEATABLE READ 부정합이 발생하지 않는다.

간단히 말하면, 자신의 트랜잭션 번호보다 앞에 있는 트랜잭션의 커밋 사항에 대한 내용만 조회가 가능한 것이다.

이 격리 수준은 트랜잭션이 시작된 시점의 데이터를 일관되게 보여주는 것을 보장해야 하기 때문에 한 트랜잭션의 실행 시간이 길어질 수록 해당 시간만큼 계속 멀티 버전을 관리해야 한다. 그러나 실제로 그렇게 긴 시간동안 수행되는 트랜잭션은 매우 드물기 때문에 READ COMMITTED 격리 수준과 비슷한 성능을 보인다.

REPEATABLE READ에서의 부정합

UPDATE 부정합

1번 트랜잭션에서 seunghwan을 조회하고, 2번 트랜잭션에서 seunghwan을 조회한 후, seunghwan을 sh로 UPDATE한 후 커밋을 한 후, seunghwan이라는 이름을 hsh으로 변경하는 코드가 있다고 가정해보자.

sh로 UPDATE한 후 커밋을 하면, seunghwan의 내용을 언두로그에 남겨야 한다. 그래야 1번 트랜잭션에 일관된 데이터를 보장한다.

UPDATE문을 수행하기 위해서는 변경을 수행할 로우를 잠금처리 해야 하는데, 1번 트랜잭션이 바라보고 있는 seunghwan은 레코드 데이터가 아니라 언두영역의 데이터이므로 잠금처리가 되지 않는다.

그래서 seunghwan을 hsh로 변경하기 위해 seunghwan을 찾아보지만, 해당 레코드는 존재하지 않으므로 이름은 sh로 남게 된다.

DML 구문은 멀티버전을 관리하지 않는 것을 알 수 있다.

Phantom READ

하나의 트랜잭션에서 같은 쿼리를 두 번 실행했을 때 첫번째 쿼리에는 없던 Phantom 레코드가 두번째 쿼리에는 보이는 현상을 말한다.

REPEATABLE READ 이하의 격리 수준에서만 발생하고, INSERT에 대해서만 발생한다.

1번 트랜잭션에서 Member 테이블을 조회하였을 때 반환 결과가 0개라고 가정한다. 2번 트랜잭션에서 Member 테이블에 1, seunghwan, Seoul 이라는 로우를 추가하고 커밋한다. 그 후에 Member 테이블을 조회하면 결과가 0개이고, id가 1인 로우의 이름을 sh로 UPDATE한 후에 다시 Member 테이블을 조회하면 결과가 1개가 된다.

REPEATABLE READ에 의해 원래는 출력되면 안되지만, UPDATE문의 영향으로 출력이 된다.

그러나 INSERT가 아닌 DELETE의 경우에는 Phantom READ가 발생하지 않는다.

SERIALIZABLE

SERIALIZABLE은 가장 단순하고 가장 엄격한 격리 수준이다. InnoDB에서 기본적으로 순수한 SELECT 작업에는 아무런 잠금을 걸지 않는데, SERIALIZABLE의 경우에는 SELECT 작업에도 공유 잠금을 설정한다. 이 경우 동시에 다른 트랜잭션이 이 레코드를 변경하지 못하게 된다. 이러한 특성 때문에 동시 처리 능력이 떨어지고, 성능 저하로 이어진다.

profile
꾸준함을 꿈꾸는 SW 전공 학부생의 개발 일기

0개의 댓글