데이터베이스에서의 Lock이란?
Lock이란 데이터의 일관성과 무결성을 유지하기 위해 트랜잭션의 순차적 진행을 보장해주는 방법입니다. (= 잠금)
데이터베이스 Lock Level
데이터베이스에서의 Lock 여러 Level을 갖습니다.
Lock Level은 잠금이 요청되거나 사용될때의 리소스에 대한 범위를 설정합니다.
- Database Level
데이터베이스 범위의 Lock은 데이터베이스 전체가 잠기게 됩니다.
해당 기능은 일반적으로 사용하지 않으며, 보통 스키마를 변경하거나 DB의 소프트웨어 버전을 올리는 등에 사용됩니다.
- Table Level
테이블을 기준으로 Lock을 설정합니다. 테이블 전체와 관련 인덱스까지 모두 잠깁니다.
이는 테이블의 모든 행을 업데이트 하거나 전체 테이블에 영향을 주는 변경을 수행할때 사용됩니다.
DDL(create, alter, drop 등) 구문과 함께 사용되며 DDL Lock이라고도 불립니다.
- Page Level
페이지를 기준으로 Lock을 설정합니다.
보통 DB에 저장되는 데이터는 8KB 단위의 블럭을 단위로 저장되는데, 이를 페이지라고 불립니다.
- Row Level
가장 세분화된 잠금 수준으로 1개의 행을 기준으로 Lock을 설정합니다.
DML(insert, update, delete 등) 에 대한 Lock으로 가장 일반적으로 사용됩니다.
데이터베이스 Lock 종류
- Exclusive (X) Lock (= 베타 락, Write Lock)
베타 락은 데이터에 변경을 가하는 쓰기 명령들에 대해 주어지는 락으로 Write Lock으로도 불리며, X로 표기합니다.
즉, 트랜잭션이 데이터를 변경할때 잠금합니다.
베타 락은 이름처럼 다른 트랜잭션이 해당 자원에 접근(ex, SELECT, INSERT..) 하는 것을 막습니다.
오직 하나의 트랜잭션만이 데이터에 대한 잠금을 걸 수 있다는 특징이 있습니다.
- Shared (S) Lock (= 공유 락, Read Lock)
공유 락은 데이터를 변경하지 않는 읽기 명령에 대해 주어지는 락으로 Read Lock이라고도 불리며 Shared의 앞 글자를 따서 주로 S로 표기합니다. 즉, 트랜잭션이 데이터를 읽기 동안에만 잠금합니다.
여러 사용자가 동시에 데이터를 읽어도 데이터의 일관성에는 아무런 영향을 주지 않기 때문에, 공유 락끼리는 동시에 접근이 가능합니다.
- Intent (I) Lock (=내재 락)
내재 락은 트랜잭션이 대상 데이터에 잠금을 걸 수 있을지 없을지를 신속히 판단할 수 있게 도와주는 잠금입니다.
내재 락은 공유 락과 베타 락 앞에 I 기호를 붙인 IS, IX, SIX 등이 있습니다.
- Intent exclusive (IX) Lock (= 의도적 베타적 잠금)
- Intent shared (IS) Lock (= 의도적 공유 잠금)
- Shared intent exclusive (SIX) Lock (= 공유 및 의도적 베타적 잠금)
예를 들자면,
사용자 A가 테이블의 하나의 로우(row)에 대해 베타 락(X)을 건 경우, 사용자 B가 테이블 전체에 대한 락을 걸기 위해서는(ex, 스키마 변경) 사용자 A의 트랜잭션이 끝날 때까지 기다려야 합니다.
그러나, 사용자 B가 테이블에 락(DDL Lock)을 걸 수 있는지 여부를 파악하기 위해 테이블에 존재하는 모든 로우와 관련된 락을 찾아보는 것은 매우 비효율적인 작업입니다.
따라서, 데이터베이스는 사용자 A가 로우에 베타 락(X)을 거는 시점에, 해당 로우의 상위 객체들(ex, 페이지, 테이블)에 대한 내재 락(IX)을 걸어, 다른 사용자가 더 큰 범위의 자원들에 대해 락을 걸 수 있는지 여부를 빠르게 파악할 수 있도록 돕습니다.
- Update (U) Lock
업데이트 락은 데이터를 수정하기 위해 베타 락(X)을 걸기 전, 데드 락을 방지하기 위해 사용되는 락입니다.
일반적으로 업데이트 락은 UPDATE 쿼리의 필터(WHERE)가 실행되는 과정에서 적용됩니다.
Optimistic Lock과 Pessimisitc Lock
- Optimistic Lock (낙관적 락)
말 그대로 트랜잭션 충돌이 발생하지 않는다는 가정을 하는게 낙관적 락입니다.
DB가 제공하는 락 기능을 사용하지 않고 JPA가 제공하는 버전 관리 기능을 사용합니다. (@Version)
즉, 어플리케이션이 제공하는 락이라고 볼 수 있습니다.
트랜잭션을 커밋하기 전까지 트랜잭션 충동을 알 수 없다는 점이 있습니다.
@Entity
public class Board {
@Id
private String id;
private String title;
@Version
private Integer version
}
위와 같은 Board 엔티티에서, 엔티티를 수정할때마다 version 필드가 자동으로 증가합니다.
그리고 엔티티를 수정할 때 조회 시점의 버전과 수정 시점의 버전이 다르면 예외를 발생시키는 것입니다.
예를 들어, 사용자 A와 사용자 B가 동일한 게시글을 수정한다고 가정해보겠습니다.
A가 먼저 게시글을 다 수정하고 B가 수정을 하게 되면 version이 다르므로 (A가 수정하게 되면서 version값이 증가) 예외가 발생하게 됩니다.
- Perssimistic Lock (비관적 락)
낙관적 락과 반대로 트랜잭션의 출동이 발생한다고 가정하고 락을 겁니다.
DB가 제공하는 락 기능을 사용합니다. 데이터를 수정 시 즉시 트랜잭션 충돌을 알 수 있습니다.
위에 설명한 Exclusive Lock과 Shared Lock이 포함됩니다.
예상 질문
- 낙관적 락과 비관적 락에 대해서 알고 있는지?
- X Lock(배타 락)과 S Lock(공유 락)의 차이
- 데이터베이스의 Lock Level이란?
- 어플리케이션에서 락을 거는 방법 (낙관적 락), DB단 에서 락을 거는 방법 (비관적 락)
'데이터베이스' 카테고리의 다른 글
SQL과 NoSQL (0) | 2022.04.01 |
---|---|
데이터베이스 인덱스(Index) 개념 정리 (0) | 2022.01.17 |