Skip to content

Latest commit

 

History

History
63 lines (35 loc) · 3.59 KB

File metadata and controls

63 lines (35 loc) · 3.59 KB

5.4.3 Repeatable Read

Inno DB 에서 가장 기본으로 사용되는 격리 수준이다.

이 격리 수준에서는 트랜잭션이 Rollback될 가능성에 대비해 변경되기 전 레코드를 언두 공간에 백업해두고 실제 레코드 값을 변경한다. 이러한 변경 방식을 MVCC라고 한다!

MVCC

Multi Version Concurrency Control 참조. 4.2.3절

언두 영역에 백업된 이전 데이터를 항상 이용해 동일 트랜잭션 내에서는 동일한 결과를 보여주는 것을 보장한다!

사실 READ COMMITTED도 MVCC를 이용해 COMMIT되기 전 버전을 보여주는데, 몇 번이나 이전 버전을 찾아 들어가느냐의 차이가 있다.

언두 영역은 주기적으로 삭제된다. 그런데 REPEATABLE READ에서는 MVCC를 보장하기 위해 가장 오래된 트랜잭션 번호보다 앞선 언두 영역의 데이터는 삭제할 수 없다.

나의 궁금증: 여기서 앞선이라는 말은, 가장 오래된 트랜잭션보다 더 오래된 언두 영역의 데이터라는 뜻일까? 그러면 그냥 지워도 되지 않을까? 앞선이 아니라 '나중에 생성된'이 맞지 않나? <- 밑에서 해결!

그림을 보면 이해된다!

6번 트랜잭션 -> Lara 생성
10번 -> Lara 조회 -> Lara 리턴
12번 -> Lara를 Toto로 조회
10번 -> Lara 조회 -> Lara 가 여전히 리턴되어야 한다!

그렇지만 Lara를 조회하면 Toto가 있을 뿐이다.
그렇지만 Toto는 12번에 의해서 변경되었다. 때문에 10번은 자기 후임 트랜잭션이 건드린 결과는 받지 않는다. 때문에 Toto의 언두로그를 찾아본다.

Lara를 발견했다! 이 로그는 6번에 의해서 만들어졌다.
따라서 10번 트랜잭션은 안심하고 선임의 결과물을 가져간다.

SELECT 쿼리는 트랜잭션 번호가 자기의 번호보다 작은 것들만 찾는다.

따라서, 12번 트랜잭션이 아직 닫히지 않았으면, 6번 언두로그는 삭제할 수 없다!

그래서 12번을 빨리 닫아줘야 언두로그를 빨리 빨리 정리할 수 있다.

하지만 여전히 문제점이 존재한다! Phantom Read

SELECT for update 를 했는데 레코드 2개가 왔다. 그런데 누군가가 레코드를 하나 추가했다.

SELECT for update를 한 번 더 했는데 레코드 3개가 왔다!

도대체 왜 이런 현상이 벌어지는 것일까?

그냥 자기보다 짬이 낮은 트랜잭션이 추가한 친구는 걸러내면 되는 것 아닐까...?

select for update 쿼리는 레코드에 쓰기 잠금을 걸어야 하는데, 언두 레코드에는 쓰기 잠금을 걸 수가 없다. 그래서 select for update 는 언두 영역의 변경 전 데이터를 가져오는 것이 아니라, 현재 레코드의 값을 가져오는 것이다.

책의 설명을 이해하기 힘들다 ㅠㅠ 책의 그림에는 레코드가 추가된 경우에 팬텀 리드가 발생하는 것을 보여준다. 그런데 책의 설명에는 이게 언두로그를 읽지 않기 때문에 발생하는 문제라고 한다. 설명이 잘못된 것 같다. 팬텀리드에 대해 더 찾아봐야 할 것 같다.

mysql 공식 레퍼런스와 많은 자료들을 찾아본 결과 이유를 알았다.

sql - How to produce "phantom read" in REPEATABLE READ? (MySQL) - Stack Overflow

위 링크에서 Super Kai의 답변 (MySQL) - Stack Overflow

그리고 select for update 를 할때만 이러한 현상이 발생하는 것도 아니라, update 전반에서 발생한다...