REPEATABLE READ

게시일
3/30/2018
Tags
development
development>DB
1. Isolation Level
여러개의 트랜잭션에서 변경되고 수행되는 쿼리가 동시에 일어났을 때, 성능과 신뢰, 일관성 사이에서 균형을 잡는 수준이다. 예를 들어서 한 트랜잭션에서 A라는 데이터를 수정하고 아직 커밋이 되지 않은 경우, 다른 트랜잭션은 A라는 데이터에 락을 걸어 접근할 수가 없게 할 수 있다(Read Committed Isolation Level인 경우). 반면 Isolation Level을 조정하여, 한 트랜잭션에서 A라는 데이터를 B라고 수정하고 아직 커밋이 되지 않은 경우, 다른 트랜잭션은 B라는 데이터에 접근할 수 있게 할 수도 있다(Read Uncommitted) 이렇게 위에 예시로 든 2개를 포함하여 총 4개의 Level이 존재하는데, 이 중에서 innoDB의 기본값인 Repeatable Read Isolation Level에 대해서 설명하고자 한다.
2. Repeatable Read Isolation Level
하나의 트랜잭션내에서 첫 번째 SELECT 쿼리가 실행되었을 때 스냅샷을 찍어서 타 트랜잭션의 변경사항과 상관없이 SELECT 결과를 계속해서 같은 상태로 보여주는 것이다. 예를 들어 아래와 같은 테이블이 있다고 가정해 보자.
CREATE TABLE `table_1` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `val` tinyint(3) unsigned DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SQL
그리고 아래와 같이 (1), (2) (3) 순으로 쿼리가 실행되었다고 가정해 보자
## A 트랜잭션 START TRANSACTION; SELECT * FROM table_1 WHERE id = 1; # (1) => 결과가 (id =1, val = 5) 나왔다고 가정. SELECT * FROM table_1 WHERE id = 1; # (3) => B 트랜잭션의 (2)에서 update가 이루어졌지만 repeatable isolation level에 의해 (1)의 결과와 동일하게 나옴 COMMIT; # B 트랜잭션 START TRANSACTION; UPDATE table_1 SET val = 2018 WHERE id = 1; # (2) => (1) 에서 select 했던 row의 데이터를 변경함 COMMIT;
SQL
여기에서 주의해야 할 것이 있는데, 바로 첫 SELECT 쿼리가 실행되었을 때 스냅샷을 찍는다는 것이다. 아래 두가지 예시를 비교해보면 이해가 될 것이다.
1) 첫번째 예시
## A 트랜잭션 START TRANSACTION; SELECT * FROM table_1 WHERE id = 500; # (1) => 해당 row가 비어서 empty set이 나왔다고 가정 SELECT * FROM table_1 WHERE id = 500; # (3) => (1)과 동일하게 empty set이 나옴. (1)의 첫 SELECT 쿼리에서 스냅샷을 찍고 스냅샷의 데이터를 읽기 때문에 계속해서 동일하게 (1)번의 결과가 나옴 COMMIT; ## B 트랜잭션 START TRANSACTION; INSERT INTO table_1 (`id`, `val`) VALUES(500, 999); # (2) => id=500에 데이터를 새로 추가해 줌 COMMIT;
SQL
2) 두번째 예시
위의 첫번째 예시와 동일하게 id=500인 row가 없다고 가정.
## A 트랜잭션 START TRANSACTION; INSERT INTO table_1 (`id`, `val`) VALUES(200, 300); # (1) => id=500과 상관없는 데이터를 삽입. SELECT * FROM table_1 WHERE id = 500; # (3) => (id = 500, val = 999) 데이터가 나옴 (3)번 이전에 스냅샷을 찍은적이 없기에 B 트랜잭션의 (2)에서 새로 추가된 값을 읽음 COMMIT; ## B 트랜잭션 START TRANSACTION; INSERT INTO table_1 (`id`, `val`) VALUES(500, 999); # (2) => id=500에 데이터를 새로 추가해 줌 COMMIT;
SQL
Today