기초 지식/DB

[JPA] 낙관적 Lock, 비관적 Lock

MarrRang 2024. 1. 5. 12:14

개요

JPA에는 동시에 여러 사용자가 접근하여 데이터를 조작할 때 발생할 수 있는 문제를 다루기 위해 Lock을 지원하고 있습니다.

이 중에 낙관적 Lock(Optimistic Lock), 비관적 Lock(Pessimistic Lock)에 대해서 알아보려 합니다.

 

낙관적 Lock

낙관적이란 단어에서 알 수 있듯이 데이터 갱신 시 충돌이 발생하는 것을 막는 것이 아닌 충돌이 일어났을 때 처리하는 Lock입니다.

 

@Entity
class Book(
    @Id
    val bookId: String,
    val bookName: String,
    
    @Version
    val version: Int
)

 

JPA에서는 위와 같이 Entity에 version 필드를 지정하여 사용합니다. version 값을 통해서 Entity의 변경사항을 감지하고 이 값이 일치하지 않을 시 문제가 생겼다고 판단하는 방식을 사용합니다.

Select 후 트랜잭션이 업데이트를 처리하기 전에 version 값을 다시 확인합니다. 그 과정에서 version 값이 일치하지 않으면 OptimisticLockException을 발생시킵니다.

낙관적 Lock의 Mode

NONE

모드를 특별히 적용하지 않고 Entity에 @Version 어노테이션이 적용된 필드가 있다면 낙관적 Lock이 적용됩니다.

OPTIMISTIC(== READ)

낙관적 Lock은 기본적으로 데이터 갱신(Update) 시에만 적용됩니다. Optimistic 모드를 사용하면 조회(Read) 시에도 적용됩니다.

OPTIMISTIC_FORCE_INCREMENT(== WRITE)

기본적인 낙관적 Lock을 적용시키면서 Version 값을 강제로 증가시키는 모드입니다.

 

비관적 Lock

낙관적 Lock과는 반대로 충돌이 발생하는 것을 미연에 방지하는 것을 목표로 하는 Lock입니다. 데이터 정합성을 지키는데 낙관적 Lock보다 좋지만 성능상 안 좋을 수 있습니다.

 

비즈니스 로직 상에서는 비관적 Lock은 낙관적 Lock보다도 쉽게 적용 가능합니다. 비관적 Lock은 데이터베이스 수준의 잠금을 포함하기 때문입니다. 그렇지만 락을 획득하고 해제하는 것을 적절히 처리해야 하는 방식입니다. 사용 방법은 아래와 같이 @Lock 어노테이션을 활용합니다.

 

interface BookRepository: JpaRepository<Book, String> {

    @Lock(LockModeType.PESSIMISTIC_WRITE)
    @Query("select b from Book b where b.bookId = :bookId")
    fun findByBookIdForUpdate(bookId: String): Book
    
}

 

비관적 Lock의 Mode

PESSIMISTIC_READ

다른 트랜잭션에게 읽기만 허용하는 모드입니다. DB의 Shared Lock을 이용해서 Lock을 적용합니다. 단, Shared Lock을 지원하지 않으면 PESSIMISTIC_WRITE와 동일하게 작동합니다.

PESSIMISTIC_WRITE

Row Exclusive Lock을 사용해서 Lock을 적용하고 다른 트랜잭션에서 읽기, 쓰기 모두 제한됩니다.

PESSIMISTIC_FORCE_INCREMENT

PESSIMISTIC_WRITE와 동일하게 Row Exclusive Lock을 사용하고 Lock 적용 동시에 version 값을 증가시킵니다.

 

정리

  낙관적 락 (Optimistic Lock) 비관적 락 (Pessimistic Lock)
동작 원리 버전(Version)이나 타임스탬프를 사용하여 충돌을 감지 레코드나 트랜잭션을 명시적으로 Lock
Lock 획득 시점 트랜잭션 커밋 시에 Lock 획득 트랜잭션 시작 시에 Lock 획득
Lock 충돌 발생시 충돌 감지 후 롤백 및 예외 발생 락 충돌 시 다른 트랜잭션이 기다림
데이터 수정시 Lock 여부 데이터 수정 시에 Lock을 걸지 않음 데이터 수정 시에 Lock을 걸어 다른 트랜잭션이 기다림
성능 낙관적 Lock은 리소스 경쟁이 적고 Lock으로 인한 성능 저하가 적다 비관적 Lock은 오버헤드로 인한 성능 저하가 높음
트랜잭션 동시성 Lock 충돌이 발생할 가능성이 높다 Lock 충돌은 적지만 Lock을 획득한 트랜잭션을 기다려야만 다음 트랜잭션 처리 가능
반응형