스터디/MySQL

MySQL의 격리 수준

jossiya 2023. 3. 23. 10:24

   MySQL은 네 가지 격리 수준을 지원합니다. 이들 격리 수준은 동시성 제어를 위한 방법을 제공하며, 다중 트랜잭션 처리에 필수적입니다. 여러 트랜잭션이 다른 트랜잭션에서 벼경하거나 조회하는 데이터를 볼 수 있게 허용할지 말지를 결정하는 것입니다.

 

 

READ UNCOMMITTED

  격리 수준에서는 그림 과 같이 각 트랜잭션에서의 변경내용이 COMMIT이나 ROLLBACK 여부에 상관없이 다른 트랜잭션에서 보입니다. 다른 트랜잭샨이 사용자 B가 실행하는 SELECT 쿼리의 결과에 어떤 영향을 미치는 지 볼 수 있습니다.

가장 낮은 격리 수준으로, 다른 트랜잭션에서 변경 중인 데이터를 읽을 수 있습니다. 이러한 현상을 Dirty Read라 합니다.

 

READ COMMITTED

  ORACLE 에서 기본적으로 사용되며 ,온라인 서비스에서 가장 많이 사용되는 격리 수준이며, Dirty read같은 상황은 발생하지 않습니다.

어떤 트랜잭션에서 데이터를 변경했더라도 COMMIT이 완료된 데이터만 다른 트랜잭션에서 조회할 수 있기 때문입니다.

NON-REPEATABLE READ(REPEATABLE READ 가 불가능하다)라는 부정합 문제가 있습니다.

  A용자와 B사용자가 하나의 트랜잭션에서 SELECT 쿼리를 실행했을 때 항상 같은 결과값이 나와야 하는 "REPEATABLE READ" 정합성에 어긋나게 됩니다.

 

REPEATABLE READ

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

언두(Undo) 공간에 백업해두고 실제 레코드 값을 변경 하며 이러한 변경 방식을 MVCC라고 하고, REPEATABLE READ는 이 MVCC(Multi Version Concurrency Control)를 위해 언두 영역에 백업된 이전 데이터를 이용해 동일 트랜잭션 내에서는 동일한 결과를 보여줄 수 있게 보장합니다.

READ COMMITTED도 MVCC를 이용해 COMMIT되기 전에 데이터를 보여주고 차이는 언두 영역에 백업된 레코드의 여러 버전 가운데 볓 번쨰 이전 버전까지 찾아 들어가야 하느냐에 있습니다.

  앞서 말한 것처럼 트랜잭션 안에서는 모든 결과값이 같아야하지만 아래 그림을 보면 결과는 서로 다름니다. 이렇게 다른 트랜잭션에서 수행한 변경잡업에 의해 레코드가 보였다 안 보였다 하는 현상을 PHANTOM READ 또는 PHANTOM ROW라 합니다.SELECT ... FOR UPDATE 쿼리는  SELECT하는 레코드에 쓰기 잠금을 걸어야 하는데, 언두 레코드에는 잠금을 걸 수 없습니다. 그래서 SELECT ... FOR  UPDATE나 SELECT ... LOCK IN SHARE MODE로 조회되는 레코드는 언두 영역의 변경 전 데이터를 가저오는 것이 아니라 현재 레코드의 값을 가져오게 되는 것입니다.

SERIALIZABLE

  가장 단순한 격리 수준이며 동시에 가장 엄격한 격리 수준입니다.

PHANTOM READ 현상을 방지하기 위해 트랜젝션이 완전히 종료될 때까지 다른 트랜잭션에서 해당 데이터에 대한 작업을 수행하지 못하도록 제한합니다. 이 격리 수준에서는 다른 모든 격리 수준에서 발생하는 현상이 발생하지 않습니다.

하지만 InnoDB 스토리지 엔진에서는 갭 락과 네스트 키 락 덕분에 REPEATABLE READ 격리 수준에서도 이미 "PHANTOM READ"가 발생하지 않기 때문에 굳이 SERIALIZABLE을 사용할 필요성은 없어 보입니다.