개요
데이터베이스에 대한 공부를 할 때 락에 대한 학습은 필수적이다.
그런데 이 락이라는 기술도 여러 가지 특징을 가진 기술로 세분화되어 있다.
오늘은 그 중에서 낙관적 락과 비관적 락에 대해 정리해 보겠다.
낙관적 락
낙관적 락이란 데이터의 충돌이 드물 것이라고 가정하고 따로 자원의 동시 접근은 허용하되, 데이터의 충돌(같은 자원 수정)이 발생할 경우 이를 감지하고 실패처리하는 것이다.
데이터의 충돌을 감지하는 방법은 테이블 내에 별도의 칼럼을 추가하는 방법이 있다.
아래의 코드는 Board라는 엔티티에 @Version 어노테이션을 사용해 충돌 감지용 칼럼을 추가한 것이다.
@Entity
public class Board {
@Id
private Long id;
@Version
private int version;
private String title;
}
낙관적 락을 적용할 경우, 작업이 수행되는 과정은 아래와 같다.
1. 스레드 1에서 id=2인 게시글 정보를 조회한다.
2. 스레드1이 조회한 데이터를 토대로 작업을 수행할 때, 스레드2도 id=2인 게시글 정보를 조회한다.
3. 데이터를 늦게 조회한 스레드2의 작업이 먼저 종료되어, 변경 내용을 테이블에 반영한다. 이 과정에서 version 컬럼이 갱신된다.
4. 스레드1도 작업이 종료되어 변경 내용을 테이블에 반영하려고 했지만, 조회할 시기의 version과 현재 테이블에 저장된 데이터의 version이 다르기 때문에 에러가 발생한다.
비관적 락
비관적 락은 낙관적 락과 반대로 데이터의 충돌이 자주 발생할 것이라 판단해 자원에 대해 동시 접근을 제어하는 방식이다.
동시 접근을 아예 막는 것이 아니라 제어한다고 표현하는 이유는 락의 종류에 따라 자원에 대해 읽기와 쓰기 작업을 제한하거나 동시에 접근하는 것을 허용할 수 있기 때문이다.
비관적 락에서 사용되는 락의 종류는 다음과 같다.
공유 락, 조회 락(Shared Lock)
공유 락은 데이터를 읽을 때 사용되는 락이다. 이런 공유 락은 공유 락끼리는 동시에 접근이 가능하다.
베타 락(Exclusive Lock)
다른 세션이 데이터에 변경을 가하는 쓰기 명령들에 주어지는 락이다. 다른 세션은 락이 해제될 때까지 해당 리소스에 접근할 수 없다. 주로 INSERT, UPDATE, DELETE와 같이 테이블의 상태를 변경하는 작업에 사용되는 락이다.
업데이트 락(Update Lock)
데이터를 수정할 때 사용하는 베타 락을 걸기 전, 데드락을 방지하기 위해 사용되는 락이다. 일반적으로 주로 WHERE 절에 따라 특정 데이터를 확인하거나 필터링할 때 사용된다.
낙관적 락 vs 비관적 락
특징 | 낙관적 락 (Optimistic Lock) | 비관적 락 (Pessimistic Lock |
접근 방식 | 충돌 가능성을 낮게 봄 | 충돌 가능성을 높게 봄 |
동작 방식 | 충돌 발생 시 이를 감지하고 처리 | 데이터 접근 시 미리 락을 설정 |
성능 | 충돌이 적으면 효율적 | 트랜잭션이 많으면 성능 저하 |
충돌 처리 | 충돌 시 업데이트 실패로 대응 | 충돌을 사전에 방지 |
데드락 | 데드락 발생하지 않음 | 락으로 인해 데드락 가능성 있음 |
적합한 상황 | 읽기 작업이 많고, 충돌이 적은 경우 | 동시 쓰기 작업이 빈번한 경우 |
물론 실제 개발환경에선 비관적 락이 많이 사용된다.
왜냐하면 조회 성능이 저하되더라도 데이터베이스의 무결성을 더 안전하게 지킬 수 있기 때문이다.
또한 비관적 락에서 문제가 발생할 경우 그냥 롤백하면 손쉽게 데이터베이스의 무결성을 지킬 수 있다.
하지만 낙관적 락에서 문제가 발생했고, 진행 중이던 작업이 여러 테이블에 걸쳐있는 작업이라면 롤백하기 굉장히 까다로울 수 있다. 왜냐하면 낙관적 락에서 롤백은 개발자가 직접 해야 하기 때문이다.
이처럼 낙관적 락과 비관적 락 모두 구현하고자 하는 기술의 특성에 맞게 잘 선택해야 할 것 같다.
'개발 일기' 카테고리의 다른 글
[개발 일기] 2025.01.26 - 논리적 동치성 (Feat : equals()) (1) | 2025.01.26 |
---|---|
[개발 일기] 2025.01.25 - volatile (1) | 2025.01.25 |
[개발 일기] 2025.01.23 - 직렬화 (0) | 2025.01.23 |
[개발 일기] 2025.01.22 - static (0) | 2025.01.22 |
[개발 일기] 2025.01.21 - TCP/IP (0) | 2025.01.21 |