복수의 쿼리를 연속적으로 사용하는 경우 일관성 있는 형태의 한 단위로 묶어서 취급하는 것.
단수 쿼리 하나로도 트랜잭션을 만들 수는 있다.
MySQL의 InnoDB만 사용가능하다. (MyISAM은 X)
트랜잭션이 가져야하는 속성 네가지를 묶어서 부르는 말
위에서 복수 트랜잭션은 서로 독립적으로 모순 없이 실행되어야 한다고 했다.
안 좋은 Isolation 예시를 보자.
아래에서 각 사용자가 하나의 트랜잭션에 대입된다.
실제로 2명이 방을 예약했지만 빈 싱글룸 수가 1개만 줄어든다.
그렇다면 좋은 Isolation 예시는 무엇일까?
바로 잠금(Lock)을 통해 후속 처리를 블록(Block)하는 것이다.
1. 사용자 A가 빈 싱글름 수를 가져온다. (SELECT ~ FOR UPDATE 사용)
2. 사용자 B는 SELECT ~ FOR UPDATE로 인해 대기한다.
3. 사용자 A가 빈 싱글룸 수를 -1 연산 후 9로 UPDATE한다.
4. 사용자 B가 빈 싱글룸 수를 가져온다.
5. 빈 싱글룸 수를 -1 연산해 8로 UPDATE한다.
6. 모든 처리가 끝난 후 빈 싱글룸 수가 8인 상태가 된다.
이렇게 병렬로 실행되지 않고 차례대로 실행되는 상태에서는 모든 트랜잭션이 모순 없이 독립적으로 처리됨을 보장할 수 있다.
그리고 이것은 Transaction 격리 수준에서 Serializable(직렬화 가능) 단계를 의미한다.
하지만 이 직렬화 가능 단계에서는 항상 동시에 동작하는 트랜잭션이 1개가 되어 성능면에서 실용적이지 못하다.
따라서 이 격리 수준을 단계별로 완화해 총 4개의 격리 수준을 정의했다. (ANSI에서 정한 규격)
1. Read Uncommitted (커밋되지 않은 읽기)
2. Read Committed (커밋된 읽기)
3. Repeatable Read (반복 읽기)
4. Serializable (직렬화 가능)
번호가 커질수록 다른 트랜잭션의 영향을 받는 것을 허용하는 수준이 엄격해진다.
이렇게 격리 수준을 완화함에 따라 일어나는 현상들이 있다.
각 현상과 격리 수준의 관계는 다음과 같다
Dirty Read | Fuzzy Read | Phantom Read | |
---|---|---|---|
Read UnCommitted | O | O | O |
Read Committed | X | O | O |
Repeatable Read | X | X | O |
Serializable | X | X | X |
먼저 격리 수준을 Fuzzy Read가 나타날 수 있는 Read Committed로 변경해야 한다.
MySQL에서 transaction isolation level은 아래와 같이 명령문을 입력하여 변경 가능하다.
set transaction isolation level read committed;
시간 흐름 | 세션 A | 세션 B |
---|---|---|
1 | ![]() | |
2 | ![]() | |
3 | ![]() | |
4 | ![]() |
Transaction A가 [시간 흐름 2]와 [시간 흐름 4] 두 번에 걸쳐 동일한 쿼리를 실행했으나 결과값이 달라진 걸 확인할 수 있다.
그렇다면 Repeatable Read는 위와 동일한 상황에서 어떻게 될까?
먼저 아래 명령어를 통해 repeatable read 격리 수준으로 설정한다.
set transaction isolation level repeatable read;
시간 흐름 | 세션 A | 세션 B |
---|---|---|
1 | ![]() | |
2 | ![]() | |
3 | ![]() | |
4 | ![]() |
처음에 출력된 결과가 그대로 다시 출력되는 걸 볼 수 있다.
Repeatable Read는 이와 같이 처음으로 실행된 쿼리의 결과를 기억해두고 있다가 동일한 쿼리가 실행되면 기억해두고 있던 결과를 반환한다.
중요한 것은 Repeatable Read는 해당 Transaction이 실행되기 이전의 결과를 기억하는 게 아님.
Transaction이 시작된 후 그 안에서 한번 읽은 결과를 기억해두는 것임.
이해를 돕기 위한 예시 내용)
자세한 원리는 https://blog.naver.com/seuis398/70117922756 참고
격리 수준은 MySQL 기본 격리 수준인 Repeatable Read이다.
시간 흐름 | 세션 A | 세션 B |
---|---|---|
1 | ![]() | |
2 | ![]() | |
3 | ![]() | |
4 | ![]() | |
5 | ![]() 영향 받은 행 2행 |
[시간 흐름 1]에서 탐색 가능하던 범위는 3행이었으나, 다른 트랜잭션 B의 DELETE 처리에 의해 선택 가능한 데이터가 [시간 흐름 5]에서는 2행으로 줄은 것을 확인할 수 있다.