비관적 락 (Pessimistic Lock)


비관적 락 (Pessimistic Lock) 이란?

  • DB에서 제공하는 Lock 기능을 사용
  • 엔티티가 아닌 스칼라 타입을 조회할 때도 사용가능
  • Lock을 획득할 때까지 트랜잭션은 대기 - Lock Timeout 설정가능

JPA가 제공하는 비관적 락 옵션(LockModeType)

  • PESSIMISTIC_WRITE :  베타락, 쓰기/읽기 Lock (Non-Repeatable Read를 방지)
  • PESSIMISTIC_READ :  공유락, 읽기 Lock 
  • PESSIMISTIC_FORCE_INCREMENT : 베타락, 쓰기/읽기 Lock, 낙관적락처럼 버저닝따라서 버전에 대한 컬럼이 필요
    (하이버네이트의 경우 nowait 를 지원하는 데이터베이스에 대해서 FOR UPDATE NOWAIT 옵션을 적용하고, 그렇지 않다면 FOR UPDATE 를 적용한다)

비관적 락 옵션(LockModeType)  적용 예제

@Repository
public interface UserMasterJpa extends JpaRepository<UserMasterEntity, String> {
    /**
     * JPA가 제공하는 비관적 락 옵션(LockModeType)
     * LockModeType.PESSIMISTIC_READ
     * LockModeType.PESSIMISTIC_WRITE
     * LockModeType.PESSIMISTIC_FORCE_INCREMENT
     */
    @Lock(LockModeType.PESSIMISTIC_READ)
    Optional<UserMasterEntity> findByUserId(Long id);
}

 

Lock Timeout 적용 예제 - DBMS에서 제공안할 수 도 있음

@Repository
public interface UserMasterJpa extends JpaRepository<UserMasterEntity, String> {
    /**
     * Lock Timeout은 락을 잡고 있는 최대 시간을 설정
     */
    @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="10000")})
    @Lock(LockModeType.PESSIMISTIC_READ)
    Optional<UserMasterEntity> findByUserId(Long id);
}

 

Lock Scope 적용 예제 - DBMS에서 제공안할 수 도 있음

@Repository
public interface UserMasterJpa extends JpaRepository<UserMasterEntity, String> {
    /**
     * 락 범위(Lock Scope)를 지정
     * NORMAL : 엔터티 자체를 잠급니다. 결합된 상속과 함께 사용하면 조상도 잠김
     * EXTENDED : NORMAL 과 동일한 기능을 포함하며 조인 테이블에서 관련 엔터티를 차단할 수 있습니다.
     */
    @QueryHints({@QueryHint(name = "javax.persistence.lock.scope", value = "EXTENDED")})
    @Lock(LockModeType.PESSIMISTIC_READ)
    Optional<UserMasterEntity> findByUserId(Long id);
}

 

Lock 을 사용함에 따라 발생할 수 있는 예외

  • PessimisticLockException
    (한 번에 하나의 Lock만 얻을 수 있으며, Lock을 가져오는데 실패하면 발생하는 예외)
  • LockTimeoutException
    (락을 기다리다가 설정해놓은 wait time을 지났을 경우 발생하는 예외)
  • PersistanceException
    (영속성 문제가 발생했을 때 발생하는 예외)

사용시 주의사항

  • @Lock 어노테이션이 붙은 메서드 호출은 @Transaction 내부에서 동작함
  • 만약 @Transaction 어노테이션의 영역(Scope) 밖에서 @Lock 어노테이션이 붙은 메서드를 호출한다면 아래와 같은 에러발생
    (javax.persistence.TransactionRequiredException: no transaction is in progress)

 

+ Recent posts