티스토리 뷰

트랜잭션과 격리 레벨

  • MySQL/MariaDBInnoDB 스토리지 엔진은 트랜잭션 기능을 지원한다. 트랜잭션은 하나의 클라이언트 연결에서 실행되는 쿼리 간의 데이터의 일관성을 보장하기 위한 방법으로 클라이언트는 개별 트랜잭션마다 단계적인 격리 레벨을 선택할 수 있다. 격리 레벨이 엄격할수록 다른 트랜잭션의 영향을 받지 않는 대신 공유 잠금 시간이 길어 동시성이 떨어지며, 격리 레벨이 완화될수록 다른 트랜잭션의 영향을 받게 되어 일관성은 떨어지지만 공유 잠금 시간이 짧아 동시성은 향상된다. InnoDB가 제공하는 격리 레벨 중 가장 많이 쓰이는 대표적인 2개가 REPEATABLE-READREAD_COMMITTED이다.

REPEATABLE-READ 격리 레벨

  • REPEATABLE-READ 격리 레벨은 MySQL/MariaDB의 기본 격리 레벨이다. 일관성은 높지만 동시성은 떨어진다.
  • 현재 트랜잭션에서 SELECT 첫 실행 시점의 로우를 스냅샷으로 간직하고 있다가 트랜잭션이 종료될 때 까지 스냅샷 시점의 로우를 반환한다. 즉, 다른 트랜잭션에서 커밋된 결과와 관계 없이 항상 동일한 시점의 로우 만을 반환한다. 항상 일관되고 동일한 로우를 반환하지만 다른 트랜잭션의 결과를 무시하기 때문에 현재를 반영하지 못하고 과거의 결과를 반환할 가능성이 높다.
  • 현재 트랜잭션에서 SELECT 실행시(INSERT, UPDATE, DELETE 실행시 WHERE도 해당) 대상 로우에 대한 공유 잠금이 트랜잭션이 종료할 때까지 발생한다. 따라서 다른 트랜잭션에서 대상 로우에 대한 변경 시도시 데드락이 발생할 수 있다.

READ-COMMITTED 격리 레벨

  • READ-COMMITTED 격리 레벨은 Oracle/MSSQL의 기본 격리 레벨이다. 동시성은 뛰어나지만 일관성은 떨어진다.
  • 현재 트랜잭션에서 SELECT를 실행할 때마다 다른 트랜잭션에서 커밋된 결과가 반영된 로우를 반환한다.
  • 현재 트랜잭션에서 SELECT 실행시(INSERT, UPDATE, DELETE 실행시 WHERE도 해당) 대상 로우에 대한 공유 잠금이 해당 쿼리가 종료할 때까지만 발생한다. 따라서 다른 트랜잭션에서 대상 로우에 대한 변경 시도시 데드락이 발생할 가능성이 적다.
  • 극도의 동시적인 쓰기 작업이 요구되는 백엔드 애플리케이션이라면 REPEATABLE-READ보다는 READ-COMMITTED 격리 레벨을 사용할 것을 추천한다.

데드락과 격리 레벨

  • 데드락은 A라는 트랜잭션에서 공유 잠금이 발생한 로우에 대해 B라는 트랜잭션에서 쓰기를 시도하면 발생하는 현상이다. 데드락은 버그가 아니며 오류 또한 아니다. 단지 동시성이 요구되는 환경에서 관찰되는 현상일 뿐이다. MySQL의 권위자인 Bill Karwin은 데드락을 예방하고 완화하는 방법으로 READ-COMMITTED 트랜잭션 격리 레벨을 사용할 것과 데드락 발생시 예외보다는 해당 로직을 재시도를 할 수 있게 소스 코드를 작성할 것을 추천했다. [관련 링크]

관련 링크

댓글
댓글쓰기 폼