개요
다중 요청을 처리하는 동시성 환경에서 데이터의 정합성과 일관성을 보장하기 위해 Lock을 사용한다.
이 글에서는 Lock의 종류와 스프링 애플리케이션에서 Jpa를 활용하여 Lock을 처리하는 방법에 대해 정리한다.
락 (LOCK)
데이터베이스에는 중요한 정보가 저장된다. 따라서 무결성과 일관성, 정합성이 반드시 지켜져야 한다. 하지만, 여러 사용자(Transaction)가 동시에 자원을 획득하게 되면 문제가 생기게 될 것이다. 이러한 문제를 방지하기 위해 데이터베이스는 Lock 기능을 제공한다. 한 트랜잭션이 특정 Row에 대한 Lock을 획득하면, 다른 트랜잭션이 이를 변경할 수 없는 것이다. 이는 데이터에 대한 처리 순서를 보장하여 정합성과 무결성을 지키고 안전한 데이터 처리를 가능하게 한다.
Lock에는 크게 낙관적 락(Optimistic Lock)과 비관적 락(Pessimistic Lock)이 존재하며 비관적 락은 다시 공유락(Shared Lock) 과 배타락(exclusive Lock)으로 나뉜다.
낙관적 락 (OPTIMISTIC LOCK)
낙관적 락은 특정 데이터에 대해 DB Lock을 걸어 제어하는 방식이 아니라, 애플리케이션 또는 데이터베이스에서 버전 정보를 사용하여 다른 요청이 접근할 수 없도록 방지하는 방식이다.
이 방식은 DB Lock을 사용하지 않기 때문에, 동시성 문제가 발생하였을 때 예외를 발생시킨다.
1. 데이터베이스에 Version 컬럼을 추가하여 동시 접근을 제어한다. 스프링 배치를 사용하면 메타 테이블에 Version 컬럼이 존재하는데, 이 컬럼이 위 용도로 사용된다. 배치는 해당 Row에 낙관적 락을 적용하여 동시성을 제어한다.
-> 트랜잭션 A와 B가 1 이라는 값을 조회하였다고 가정해보자
- A는 1을 2로 변경한 후 Commit을 한다.
- B는 1을 2로 변경한 후 Commit을 시도하지만, Version 2는 이미 존재하므로 예외가 발생한다.
2. 애플리케이션에 Version 필드를 추가하여 동시 접근을 제어한다. 자바와 스프링에서는 낙관적 락을 위해 @Version 어노테이션을 지원한다. Jpa를 사용할 때 @Entity 클래스에 Long 타입의 필드를 선언한 후 @Version 어노테이션을 붙여준다.
-> 여러 트랜잭션이 동일한 데이터에 접근하여 변경을 시도할 경우 최초에 조회된 버전 정보와 현재 데이터베이스에서 조회된 버전 정보가 불일치할 경우 예외가 발생한다.
비관적 락 (PESSIMISTIC_LOCK)
비관적 락은 데이터베이스의 Lock을 사용하여 현재 사용중인 트랜잭션이 특정 데이터를 종료 시점까지 점유할 수 있도록 한다. 데이터의 정합성과 무결성을 보장하는 데 유용한 방식이지만 잘못 사용할 경우 Lock으로 인한 병목 현상이 발생할 수 있고, 서로 자원을 점유하려는 과정에서 데드락이 발생할 수도 있다.
병목: 무수히 많은 요청이 발생하였을 때 Lock으로 인해 처리 속도가 저하되는 현상
데드락: 서로 다른 두 트랜잭션이 각각 A, B 데이터에 소유권을 점유한 상태에서 상대 편의 데이터에 Lock을 획득하려 할 때 발생한다. A, B 데이터 모두 Lock이 종료되지 않았으므로 두 트랜잭션은 데이터에 대한 Lock을 획득하지 못하고 영원히 멈추게 된다.
공유 락 (Shared Lock)
공유 락은 데이터의 변경을 막고, 조회만 가능하도록 제어할 때 사용한다. 한 트랜잭션이 공유 락을 걸더라도 다른 트랜잭션이 공유 락을 획득하여 해당 레코드를 조회할 수 있다. 단, 데이터에 대한 쓰기 작업은 제한되며 락이 종료되기 전까지 레코드가 변경되지 않음이 보장된다.
SELECT * FROM Table WHERE id = 1 FOR SHARE;
배타 락 (Exclusive Lock)
공유 락이 조회를 위한 락이었다면, 배타 락은 쓰기 작업을 할 때 사용하는 락이다. 한 트랜잭션이 데이터에 대해 배타 락을 획득하게 되면, 다른 트랜잭션은 조회 및 쓰기 작업을 할 수 없다. 배타 락을 획득한 트랜잭션은 해당 트랜잭션이 종료될 때까지 데이터에 대한 배타적인 소유권을 가지게 된다.
SELECT * FROM Table WHERE id = 1 FOR UPDATE;
@Lock
spring-data-jpa는 동시성을 제어하기 위해 @Lock 어노테이션을 제공한다. 어노테이션 속성을 활용하여 낙관적 락 또는 비관적 락을 적용할 수 있다.
package org.springframework.data.jpa.repository;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.persistence.LockModeType;
/**
* Annotation used to specify the {@link LockModeType} to be used when executing the query. It will be evaluated when
* using {@link Query} on a query method or if you derive the query from the method name.
*
* @author Aleksander Blomskøld
* @author Oliver Gierke
*/
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Lock {
/**
* The {@link LockModeType} to be used when executing the annotated query or CRUD method.
*
* @return
*/
LockModeType value();
}
public enum LockModeType
{
/**
* Synonymous with <code>OPTIMISTIC</code>.
* <code>OPTIMISTIC</code> is to be preferred for new
* applications.
*
*/
READ,
/**
* Synonymous with <code>OPTIMISTIC_FORCE_INCREMENT</code>.
* <code>OPTIMISTIC_FORCE_IMCREMENT</code> is to be preferred for new
* applications.
*
*/
WRITE,
/**
* Optimistic lock.
*
* @since 2.0
*/
OPTIMISTIC,
/**
* Optimistic lock, with version update.
*
* @since 2.0
*/
OPTIMISTIC_FORCE_INCREMENT,
/**
*
* Pessimistic read lock.
*
* @since 2.0
*/
PESSIMISTIC_READ,
/**
* Pessimistic write lock.
*
* @since 2.0
*/
PESSIMISTIC_WRITE,
/**
* Pessimistic write lock, with version update.
*
* @since 2.0
*/
PESSIMISTIC_FORCE_INCREMENT,
/**
* No lock.
*
* @since 2.0
*/
NONE
}
사용 방법은 간단하다. Lock을 적용하려는 Repository 내 메서드에 어노테이션을 붙여주면 된다.
@Lock(LockModeType.PESSIMISTIC_WRITE)
Optional<Member> findById(String id);
[Database] 낙관적 락 / 비관적 락
이름 그대로 비관적 락은 자원 경쟁을 비관적으로, 낙관적 락은 낙관적으로 본다. 비관적 락은 Repeatable Read 또는 Serializable 정도의 격리성 수준을 제공한다.트랜잭션이 시작될 때 Shared Lock 또는 Ex
velog.io
https://systemdata.tistory.com/51
낙관적인 락 vs 비관적인 락
목차락이란?낙관적 락(Optimistic Lock)비관적 락(Pessimistic Lock)낙관적 락 vs 비관적 락결론1. 락이란?여러 개의 트랜잭션이 동시에 접근했을 때, 데이터의 일관성이 깨질 수 있기 때문에 락(잠금)을 걸
systemdata.tistory.com
[JPA] @Lock 어노테이션이란 무엇일까❓: 다양한 LockModeType 잠금 모드
@Lock 어노테이션이란❓@Lock 어노테이션은 Spring Data JPA에서 제공하는 기능으로, JPA 리포지토리 메소드에 적용하여 특정 데이터베이스 쿼리에 대한 잠금 모드를 지정하는 데 사용됩니다. 이 어
pixx.tistory.com
https://ksh-coding.tistory.com/121
[DB] DB Lock이란? (feat. Lock 종류, 블로킹, 데드락)
0. 락(Lock)이란? 여러 커넥션에서 동시에 동일한 자원을 요청할 경우 순서대로 하나의 커넥션만 변경할 수 있게 해주는 기능 동시성을 제어하기 위한 기능 저는 처음에 DB 락을 접했을 때, 락을 이
ksh-coding.tistory.com
JPA 에서 낙관적 락(Optimistic-Lock)을 이용해 동시성 처리하기
예제 및 테스트 코드는 github 에서 확인 가능합니다. 낙관적 락과 비관적 락의 차이점 이번엔 낙관적 락(Optimistic Lock) 을 이용해 동시성 처리를 하는 방법에 대해 알아보려 합니다. 그전에 낙관적
devoong2.tistory.com
'development > database' 카테고리의 다른 글
[DB] 트랜잭션 격리 수준과 부정합 문제 (2) (0) | 2025.03.31 |
---|---|
[DB] 트랜잭션 격리 수준과 부정합 문제 (1) (1) | 2024.12.06 |