본문 바로가기

개발/Spring

[Spring] JPA 잠금(Lock) 이해하기

최근에 데이터 동기화 관련 문제를 처리하기 위해 검색하다 찾아본 어노테이션에 대해 작성해 보려 한다.

 

문제는 increase형식에 데이터를 저장해야 하는데 spring에서 비동기로 처리된 데이터를 유실 없이 데이터 무결성을 검증하여 트랜잭션을 처리하려고 한다.

 

검색 결과,

 

@Lock annotation을 통해 트랜잭션 충돌을 방지하고 데이터에 Lock을 걸어 데이터를 보호한다.

 

잠금에는 낙관점 잠금(Optimistic Lock)비관적 잠금{Perssimistic Lock)이 있다.

 

낙관점 잠금(Optimistic Lock)

낙관적 잠금이란 트랜잭션을 처리할때 충돌이 발생하지 않을 것이라는 낙관적 가정을 하는 기법이다.

낙관적 잠금을 사용하기 위해서는 Entity 내부에 @Version Annotation이 붙은 Int, Long Type의 변수를 구현하여줌으로써 간단하게 구현이 가능하다.

 

 

@Version을 명시할때는 다음과 같은 주의사항이 있다.

  • 각 엔티티 클래스에는 하나의 버전 속성 만 있어야 합니다.
  • 여러 테이블에 매핑 된 엔티티의 경우 기본 테이블에 배치되어야 합니다.
  • 버전에 명시할 타입은 int, Integer, long, Long, short, Short, java.sql.Timestamp 중 하나 여야 합니다.

 

낙관적 잠금에는 3가지 옵션이 있다.

  • NONE : 락 옵션을 적용하지 않아도 @Version만 있으면 낙관적 잠금이 적용된다.
  • OPTIMISTIC (Read) : Entity 수정시에만 발생하는 낙관적 잠금이 읽기 시에도 발생하도록 설정한다.
    읽기시에도 버전을 체크하고 트랜잭션이 종료될 때까지 다른 트랜잭션에서 변경하지 않음을 보장한다.
    이를 통해 dirty read와 non-repeatable read를 방지한다.
  • OPTIMISTIC_FORCE_INCREAMENT (Write) : 낙관적 잠금을 사용하면서 버전 정보를 강제로 증가시키는 옵션이다.

 

비관적 잠금(Perssimistic Lock)

비관적 잠금이란 트랜잭션의 충돌이 발생한다고 가정하고 우선적으로 락을 거는 기법이다. 동시에 많은 데이터가 들어왔을 때 데이터 처리에 의한 교착상태에 빠질 수 있는 가능성이 높다고 보는 것이다. 이 경우 비관적 잠금을 통해 예외를 발생시키지 않고 정합성을 보장한다. 하지만 성능적인 면에서 느려질 가능성이 있다.

 

 

비관적 잠금은 트랜잭션이 시작될 때 데이터에 Lock을 걸고 시작한다. 다른 트랜잭션은 Lock이 걸려있어 데이터를 업데이트할 수 없다. 업데이트를 하기 위해서는 해당 트랜잭션이 종료(commit) 된 이후에 수정이 가능하다.

 

 

비관적 잠금에는 3가지 옵션이 있다.

  • PESSIMISTIC_WRITE : 배타적 잠금(Exclusive Lock)을 획득하고 데이터를 다른 트랜잭션에서 READ, UPDATE, DELETE 하는 것을 방지한다. SQL 쿼리에 SELECT FOR UPDATE 구분을 사용하면서 시작한다.
  • PESSIMISTIC_READ : 데이터를 반복 읽기만 하고 수정하지 않는 용도로 락을 걸 때 사용하며 사용하는 데이터베이스에 따라 지원 여부가 달라지므로 확인 후 사용하기 바란다.
  • PESSIMISTIC_FORCE_INCREMENT : PESSIMISTIC_WRITE와 유사하게 작용 하지만 @Version이 지정된 Entity와 협력하여 사용한다. PESSIMISTIC_FORCE_INCREMENT 잠금을 획득할 시 버전이 업데이트된다.

 

 


출처

https://velog.io/@lsb156/JPA-Optimistic-Lock-Pessimistic-Lock
https://www.baeldung.com/jpa-optimistic-locking