데이터베이스에서 동시성과 데이터 일관성을 보장하기 위해 사용되는 메커니즘이다.
데이터베이스에 접근해서 데이터를 수정할 때 동시에 수정이 일어나 충돌이 일어날 수 있다.
이러한 상황을 제어하기 위해 트랜잭션의 격리 수준과 비즈니스 로직에 맞추어 Lock이 필요하다.
데이터베이스
데이터베이스 범위의 lock은 전체 데이터베이스를 기준으로 lock 하는 것이며, 즉 1개의 세션만이 데이터베이스의 데이터에 접근이 가능한 것이다. 해당 기능은 일반적으로는 사용하지 않으며, 사용하는 때가 있다면 DB의 소프트웨어 버전을 올린다던지 주요한 DB의 업데이트에 사용한다.
파일
데이터베이스 파일을 기준으로 lock을 설정한다. 파일이란 테이블, row 등과 같은 실제 데이터가 쓰여지는 물리적인 저장소다. 해당 범위의 lock은 잘 사용되진 않는다.
테이블
테이블 수준의 lock은 테이블을 기준으로 lock을 설정한다. 이는 테이블의 모든 행을 업데이트 하는 등의 전체 테이블에 영향을 주는 변경을 수행할 때 유용하다. 즉, DDL(CREATE, ALTER, DROP)구문과 함께 사용되며 "DDL Lock"이라고 부르기도 한다.
페이지와 블록
파일의 일부인 페이지와 블록을 기준으로 lock을 설정하며, 잘 사용되진 않는다.
컬럼
테이블의 컬럼을 기준으로 lock을 설정하는 방식으로, 이 형식은 lock 설정 및 해제의 리소스가 많이 들기 때문에 일반적으로 사용되지는 않으며 지원하는 DBMS 또한 많지 않다.
행
1개의 행(Row)을 기준으로 lock을 설정하는 방식으로, DML에 대한 lock으로써 가장 일반적으로 사용하는 lock이다.

사용자 1과 사용자 2가 모두 동일한 레코드에 대한 트랜잭션 요청을 동시에 보내는 것을 관찰한다. 그러나 사용자 1의 트랜잭션이 다른 쪽에서 성공적으로 업데이트 되는 동안 사용자 2의 커밋된 트랜잭션은 거부된다. 결과적으로 트랜잭션을 재시도하기 위해 사용자 2는 먼저 현재 데이터를 읽은 다음 해당 정보를 기반으로 새 트랜잭션을 만들어야 한다.
JPA에서 Optimistic Lock을 사용하기 위해서는 Entity 내부에 @Version Annotation이 붙은 Long, Integer, Short, Timestamp Type의 변수를 구현해줌으로써 간단하게 구현이 가능하다.
여러 업데이트가 서로 간섭하지 않도록 방지하는 version 이라는 구분 속성을 확인하여 Entity의 변경사항을 감지하는 메커니즘이다.
@Entity
public class Board {
@Id
private String id;
private String title;
@Version
private Integer version;
}
엔티티를 수정하고 트랜잭션을 커밋할 때, 영속성 컨텍스트를 플러시하면서 UPDATE 쿼리를 실행한다.
UPDATE BOARD
SET
TITLE=?,
VERSION=? (버전 +1 증가)
WHERE
ID=?
AND VERSION=? (버전 비교)
데이터베이스의 버전과 엔티티의 버전이 같으면 데이터를 수정하면서 동시에 버전도 하나 증가시킨다.
그러나 이미 데이터베이스에 수정이 이루어져 두 버전이 다르면, WHERE문에서 조건이 달라지므로 수정할 대상이 없어져 이 경우 JPA가 예외를 발생시킨다.
공유 락은 데이터를 읽을 때 사용되는 Lock이다. 이런 공유 락은 공유 락 끼리는 동시에 접근이 가능하다. 즉, 하나의 데이터를 읽는 것은 여러 사용자가 동시에 할 수 있다라는 것이다. 하지만 공유 락이 설정된 데이터에 배타 락(Exclusive Lock)을 사용할 수는 없다.
배타 락은 데이터를 변경하고자 할 때 사용되며, 트랜잭션이 완료될 때까지 유지된다. 배타락은 락이 해제될 때까지 다른 트랜잭션(읽기 포함)은 해당 리소스에 접근할 수 없다. 또한 해당 락은 다른 트랜잭션이 수행되고 있는 데이터에 대해서는 접근하여 함께 락을 설정할 수 없다.

비관적 락과 낙관적 락 중 어떤 전략을 선택할지는 애플리케이션의 특성과 요구 사항에 따라 달라진다.
비관적 락은 데이터의 일관성이 매우 중요하고, 충돌이 자주 발생할 것으로 예상되는 경우에 적합하다. 왜냐하면 이 경우 데이터의 일관성과 무결성을 보장하는 것이 더 중요하기 때문이다.
반면, 낙관적 락은 동시성이 높은 환경에서 성능을 최적화하고자 할 때 유리하다. 왜냐하면 이 경우 충돌이 드물게 발생하고, 시스템의 성능을 최대한 활용하는 것이 더 중요하기 때문이다.
따라서, 애플리케이션의 요구 사항과 환경을 면밀히 분석하여, 가장 적합한 동시성 제어 전략을 선택하는 것이 중요하다.
왜냐하면 올바른 전략 선택은 데이터의 일관성을 보장하고, 시스템의 성능을 최적화하는 데 결정적인 역할을 하기 때문이다.
참조
- https://2step-hyun.tistory.com/116
- https://f-lab.kr/insight/pessimistic-vs-optimistic-locking?gad_source=1&gclid=CjwKCAjwy8i0BhAkEiwAdFaeGHivhyDsvgKKzZgcZC1-gPkDiAHgZivjBdNomzRefUE78M3UA90JcRoCg_IQAvD_BwE
- https://www.educative.io/answers/whats-the-difference-between-optimistic-and-pessimistic-locking
- https://shuu.tistory.com/88