격리 수준에 따라 발생하는 현상
트랜잭션 격리 수준에 대해 언급하기에 앞서, 트랜잭션 격리 수준에 따라 일어날 수 있는 현상을 먼저 언급하도록 하겠다.
- 더티 읽기(dirty read) : 어떤 트랜잭션이 커밋되기 전에 다른 트랜잭션에서 데이터를 읽는 현상. 사용자 a가 값을 9에서 10으로 변경하고 커밋하지 않았는데, 사용자 b가 10으로 읽는다. 확정전의 더럽혀진 데이터를 읽는다는 의미에서 붙여진 이름
- 애매한 읽기/반복 가능하지 않은 조회(fuzzy / NonRepeatable Read) : 어떤 트랜잭션이 이전에 읽는 데이터를 다시 읽을 때, 2회 이후의 특정 행 결과가 1회 때와 다른 현상. 사용자 a가 10을 읽고 사용자 b가 9로 변경해 커밋한다면, 사용자 a가 다시 select를 할 때 결과는 9다. 최초의 값인 10이 2회 이후의 select에서 보증되지 않고 애매하게 되는 것에서 붙여진 이름
- 팬텀 읽기(Phantom Read) : 어떤 트랜잭션을 읽을 때 선택할 수 있는 데이터가 나타나거나 사라지는 현상이다. 사용자 a가 특정 select 쿼리를 실행하고 사용자 b가 커밋한 후 a가 같은 쿼리를 실행할 때 다른 데이터가 선택 된다. 나타나거나 사라지는 데이터가 유령과 닮아서 붙여진 이름이다.
-> 여기서 팬텀 읽기와 애매한 읽기의 차이는, 팬텀 읽기는 레코드 추가/삭제에 대한 것이고, 애매한 읽기는 레코드 특정 행의 변경에 대한 것이다.
트랜잭션 격리 수준
격리 수준이 가장 엄격한 수준부터 느슨한 수준으로 설명하도록 하겠다.
- 직렬화 가능(Serializable) : 모든 트랜잭션이 순차적으로 직렬화 되어 수행된다면 "모순 없음"을 보장할 수 있다. 이를 dbms에서 격리 수준으로 구현하고 제공하는 것이 “직렬화 가능”이라는 사양이다. 여러 트랜잭션이 "동시에" 같은 행에 접근 불가능하므로, 뒤에서 일어난 트랜잭션은 앞이 끝날 때 까지 기다려야 한다. 따라서 교착 상태가 일어날 확률이 높고 성능이 떨어진다.
- 반복 가능한 읽기(Repeatable Read) : 하나의 트랜잭션이 조회하는 행을 다른 트랜잭션이 수정할 수 없다. 즉 트랜잭션 a가 보고 있는 행에 대한 수정 명령이 트랜잭션 b에서 일어나도, 내용이 반영되지 않고 트랜잭션 a는 이전과 동일한 결과를 갖는다. 단, 반복 가능한 읽기는 데이터의 추가는 막지 않아 "팬텀 읽기"가 발생할 수 있다. 그러나 MVCC가 자신보다 나중에 시작된 트랜잭션의 데이터 추가를 무시할 수 있어 일반적으로는 잘 발생하지 않는다. 참고
- 커밋된 읽기(read commited) : 가장 많이 사용하는 격리 수준, 커밋 완료된 데이터에 대해서만 조회를 허용한다. 이 경우 쿼리를 실행한 시점에서 커밋된 데이터를 읽어들이는데, 같은 쿼리를 복수 회 실행 중 다른 트랜잭션에서 커밋되면 최신 쿼리 실행 시점의 커밋 데이터를 읽는다. 따라서 다른 트랜잭션이 커밋을 하면 팬텀 읽기와 반복 가능하지 않은 조회가 발생할 수 있다.
- 커밋되지 않은 읽기 : 가장 낮은 격리 수준으로, 트랜잭션의 갱신 내용이 커밋되지 않아도 다른 트랜잯션에 노출된다. 그러나 대부분의 db 벤더사에서는 이를 지원하지 않는다.