반응형

(DB가 아닌) 애플리케이션 단 락에 대해 알아본다.

2023.01.12 - [개발/spring] - [jpa] lock종류와 사용 시 주의사항

 

Optimistic Locking 낙관적 락

  • @Version 어노테이션 사용(엔티티 당 하나)
  • 최초 커밋만 인정하는 방법
  • entity에 바로 락을하는 것이 아니라 버전 넘버를 저장하는 방식
    • 초기 버전 값은 0
  • 저장할 때 버전 넘버가 다르거나(해당 row못찾음) 0이면 롤백하고 에러 발생
  • intIntegerlongLongshortShortjava.sql.Timestamp
    • we can also use other approaches, such as timestamps, hash value computation, or serialized checksum.
  • 버전 애트리뷰트는 엔티티를 통해 읽을 수 있지만 절대 개발자가 직접 업데이트하거나 증가시켜선 안된다
    • 벌크 연산은 버전을 무시하기 때문에 벌크 연산을 할 경우 버전 필드를 직접 증가시켜야 한다
@Version
@UpdateTimestamp
@Column(nullable = false)
private LocalDateTime updated;

 

Pessimistic Locking 비관적 락

  • DB에서 제공하는 락기능을 사용
  • entity에 접근하는 순간 락이 걸림
  • 트랜잭션끼리의 충돌이 발생한다고 가정하고 우선 락을 거는 방법
  • @Lock 어노테이션 사용
  • 락이 실행할 때 transaction이 없으면 에러 발생(transactionRequiredException)
  • 락을 바로 얻을 수 없으면 LockTImeoutException 던짐
    • timeout 설정 필요: 락을 잡고 있는 최대 시간
      • QueryHint 이용; javax.persistence.lock.timeout; 단위 ms
    • 모든 DBMS가 지원하는 건 아님
  • If the time it takes to obtain a lock exceeds the value of this property, a LockTimeoutException will be thrown, but the current transaction will not be marked for rollback.

 

@Lock(LockModeType.PESSIMISTIC_READ)
@QueryHints({@QueryHint(name = "jakarta.persistence.lock.timeout", value = "3000")})
public Optional<Customer> findById(Long customerId);

 

 

LockModeType

public enum LockModeType {
  READ,
  WRITE,
  OPTIMISTIC,
  OPTIMISTIC_FORCE_INCREMENT,
  PESSIMISTIC_READ,
  PESSIMISTIC_WRITE,
  PESSIMISTIC_FORCE_INCREMENT,
  NONE;

 

optimistic lock 관련

  • NONE
    • 락 모드를 적용하지 않아도 엔티티에 버전 애트리뷰트가 있으면 Optimistic Locking이 적용된다
    • Second Lost Update Problem을 예방할 수 있다
    • 조회한 엔티티를 수정할 때 버전을 체크하면서 버전을 증가한다(UPDATE 쿼리 사용)
    • 이때 데이터베이스의 버전 값이 현재 버전이 아니면 예외 발생
  • OPTIMISTIC
    • NONE 을 사용하면 엔티티를 수정해야 버전을 체크하지만 OPTIMISTIC을 사용하면 엔티티를 조회만 해도 버전을 체크한다
    • 쉽게 얘기하면 한 번 조회한 엔티티는 트랜잭션을 종료할 때까지 다른 트랜잭션에서 변경하지 않음을 보장한다
    • dirty read와 non repeatable read를 방지한다
    • 트랜잭션을 커밋할 때 버전 정보를 조회해서(SELECT 쿼리 사용) 현재 엔티티의 버전과 같은지 검증하고 같지 않으면 예외가 발생한다.
  • OPTIMISTIC_FORCE_INCREMENT
    • Optimistic Locking을 사용하면서 버전 정보를 강제로 증가한다
    • 논리적인 단위의 엔티티 묶음을 관리할 떄 사용한다
    • 엔티티를 수정하지 않아도 트랜잭션을 커밋할 때 UPDATE 쿼리를 사용해 버전을 강제로 증가시킨다
    • 이때 데이터베이스의 버전이 엔티티 버전과 다르다면 예외가 발생한다
    • 추가로 엔티티를 수정하면 수정 시 버전 UPDATE가 발생한다 따라서 총 2번의 버전 증가가 나타날 수 있다

persistent lock 관련

  • LockModeType.PESSIMISTIC_WRITE
    • 일반적인 옵션. 데이터베이스에 쓰기 락
    • 다른 트랜잭션에서 읽기도 쓰기도 못함. (배타적 잠금)
  • LockModeType.PESSIMISTIC_READ
    • 잘 사용하지 않음 
    • 반복 읽기만 하고 수정하지 않는 용도로 락을 걸 때 사용
    • 다른 트랜잭션에서 읽기는 가능함. (공유 잠금)
  • LockModeType.PESSINISTIC_FORCE_INCREMENT
    • Version 정보를 사용하는 비관적 락
    • 버전 정보를 강제로 증가시킴

jpa에 위와 같이 이름으로 ForUpdate 줘도 만들어지는 쿼리는 select for update로 나가게 된다.

728x90
반응형

+ Recent posts