보통 데이터베이스에서 다중의 사용자가 하나의 데이터를 접근해서 쓰려는 경우에 생기는 문제를 막기 위해 생각할 수 있는 두가지 해결 방식이 존재한다.
- Lock 사용하기
- 트랜잭션의 고립 수준 높이기
그러나 두개는 다르다. 간단히 개념적으로 놓고 보면
- Lock
- 특정 자원에 대한 배타적 접근
- 트랜잭션
- 여러 작업의 연속적인 처리의 일관성과 데이터의 정합성 보장
가장 혼동할 수 있는 포인트는 트랜잭션의 고립 수준을 높이면, Lock과 다를바 없는 것이 아닌가? 반은 맞고 반은 틀리다.
- 엄밀히 말해 트랜잭션을 통해 접근하는 건 말 그대로 여러 작업을 그냥 하나로 묶어서 처리하겠다는 개념일 뿐이다.
- 보통 트랜잭션의 고립수준이 높아지니까 알아서 Lock을 쓰지 않아도 데이터에 대한 접근의 고립 수준을 높여주겠지 라고 생각할 수 있지만
- 실제로는 트랜잭션의 고립수준이 높아질 수록 트랜잭션이 Lock을 더 많이 거는 방식으로 대응하는 것이다.
- 즉, 트랜잭션의 고립 수준을 높이는 것을 구현하기 위해 Lock을 사용하는 것이다.
그래서 처음 질문에 돌아와서 생각해보면
- Lock 사용하기
- 트랜잭션의 고립 수준 높이기
- 위 두개는 결국 둘다 “Lock 사용하기” 하는 것과 마찬가지이다.
- 다만 Lock을 내가 직접 걸어서 Control 하냐, 트랜잭션 자체에서 매 작업에 대해 Lock을 자동으로 걸어주냐의 차이일 뿐이다.
실제 DB 에서도 트랜잭션 고립수준에 따라 Lock 거는 것이 달라지는지 확인해보자
- MySQL(InnoDB)
REPEATABLE READ
- For a unique index with a unique search condition,
InnoDB
locks only the index record found, not the gap before it. - For other search conditions,
InnoDB
locks the index range scanned, using gap locks or next-key locks to block insertions by other sessions into the gaps covered by the range. For information about gap locks and next-key locks, see Section 15.7.1, “InnoDB Locking”. SERIALIZABLE
REPEATABLE READ
에서는 Unique Index 를 사용하는 SELECT 쿼리 혹은 특정 Unique 조건 검색인 경우에 대해 Lock을 건다. 또한 Range 검색이되는 경우엔 Gap Lock을 건다.SERIALIZABLE
에서는REPEATABLE READ
와 다르게 모든 SELECT 쿼리에서 Lock 을 건다. (autocommit
옵션이 빠진 경우)
This is the default isolation level forInnoDB
. Consistent reads within the same transaction read the snapshot established by the first read. This means that if you issue several plain (nonlocking)SELECT
statements within the same transaction, theseSELECT
statements are consistent also with respect to each other. See Section 15.7.2.3, “Consistent Nonlocking Reads”.For locking reads (SELECT
withFOR UPDATE
orFOR SHARE
),UPDATE
, andDELETE
statements, locking depends on whether the statement uses a unique index with a unique search condition, or a range-type search condition.
This level is likeREPEATABLE READ
, butInnoDB
implicitly converts all plainSELECT
statements toSELECT ... FOR SHARE
ifautocommit
is disabled. Ifautocommit
is enabled, theSELECT
is its own transaction. It therefore is known to be read only and can be serialized if performed as a consistent (nonlocking) read and need not block for other transactions. (To force a plainSELECT
to block if other transactions have modified the selected rows, disableautocommit
.)
- PostgreSQL
READ COMMITTED
(PostgreSQL 은 고립수준이 Read Comitted 가 기본이다)
요약
요약: 트랜잭션 고립 수준 높이기 → 고립이 높아질수록 트랜잭션에서 Lock을 건다.