[JPA] 낙관적 락(Optimistic Lock), 비관적 락(Pessimistic Lock)
# Back-End/Spring

[JPA] 낙관적 락(Optimistic Lock), 비관적 락(Pessimistic Lock)

 

주제

  • 비관적 락과 낙관적 락에 대해 알아본다.
  • 각각 적합한 사용처를 알아본다.

 


 

1. 비관적 락, 낙관적 락

1.1 락이 왜 필요한가요?

트래픽이 낮은 서비스에서는 자주 발생하지 않겠지만, 트래픽이 많아진다면 여러 트랜잭션/요청이 동시에 같은 데이터에 접근하는 경우가 생길 수 있다.

 

이때 각기 다른 요청이 수행하는 작업은 서로의 작업 결과에 영향 끼칠 수 있다.

데이터의 일관성을 유지하기 위해 Lock을 통해 이를 제어할 수 있다.

 

 

1.1 비관적 락(Pessimistic Lock)

1.1.1 정의

자원 요청에 따른 동시성 문제가 발생할 것이라 예상하고 락을 거는 방법론
  • 트랜잭션 간에 충돌이 발생할 것이라고 가정한다.
  • 하나의 트랜잭션이 자원에 접근했을 때 락을 걸고, 다른 트랜잭션은 접근하지 못한다.
  • DB에서는 Shared Lock(공유 잠금: Select) 이나 Exclusive Lock(배타 잠금: Insert, Update, Delete)을 건다
    • S Lock : 하나의 트랜잭션이 자원을 읽는 동안 다른 트랜잭션이 S Lock은 가능하나 E Lock은 걸 수 없다.
    • E Lock : 하나의 트랜잭션이 자원을 변경할 때, 다른 트랜잭션이 S Lock, E Lock을 걸 수 없다

 

1.1.2 장/단점

  • 장점
    • 충돌이 자주 발생하는 환경에서 롤백의 횟수를 줄일 수 있어 성능에 유리
    • 데이터 무결성을 보장하는 수준이 높다
  • 단점
    • 동시성이 떨어져 성능 손해를 많이 본다.
    • 읽기가 많이 이루어지는 곳에는 적합하지 않다.
    • 데드락을 유발할 수 있다.

 

 

1.2 낙관적 락(Optimistic Lock)

1.2.1 정의

자원을 접근할 때 락을 걸지 않고, 동시성 문제가 발생할 때 처리한다는 방법론
  • 트랜잭션 간에 충돌이 발생하지 않을 것이라 가정한다.
  • 충돌이 나는 것을 막지 않고 충돌이 났을 때 처리한다.
  • Version의 상태를 통해 충돌을 확인한다.
  • 어플리케이션 단에서 처리한다.

 

1.2.2 장/단점

  • 장점
    • 충돌이 안난다는 가정하에 요청이 수행되므로 처리 성능이 좋다.
  • 단점
    • 잦은 충돌이 일어나서 처리 비용이 많이 들 때는 적합하지 않다.
    • 어플리케이션단에서 롤백 처리를 어떻게 할지 구현해야 한다.

 

 

2. JPA에서의 사용법

2.1 @Version 어노테이션을 이용한 낙관적 락(Optimistic Lock)

2.1.1 @Version 어노테이션 사용법

@Entity
public class MyDataEntity {

    ...
    
    @Version
    private Long version;

}

 

  • 엔티티 내부에 @Version 어노테이션이 붙은 변수를 통해 간단하게 구현할 수 있다.
  • 엔티티 클래스에 하나의 버전 속성만 있어야 한다.
  • 엔티티를 수정할 때 마다 Versioning이 되기 때문에 조회 버전과 수정 버전이 다르면 ObjectOptimisticLockingFailureException 예외가 발생한다.
  • 버전에 명시할 타입은 int, Integer, long, Long, shot, Short, java.sql.Timestamp 이어야 한다.
  • LockModType의 종류
    • OPTIMISTIC
      • 트랜잭션 시작 시 버전 점검이 수행되고, 트랜잭션 종료 시에도 버전 점검이 수행된다.
      • 버전이 다르면 트랜잭션이 롤백된다.
    • OPTIMISTIC_FORCE_INCREMENT
      • 낙관적 락을 사용하면서 추가로 버전을 강제로 증가시킨다.
      • 관계를 가진 다른 엔터티가 수정되면 버전이 변경된다. (ex. 댓글이 수정되면 게시글도 버전이 변경된다.)
    • READ
      • OPTIMISTIC과 동일하다.
    • WRITE
      • OPTIMSTIC_FORCE_INCREMENT와 동일하다.
    • NONE
      • 엔터티에 @Version이 적용된 필드가 있으면 낙관적 락을 적용한다.

 

 

2.2 @Lock 어노테이션을 이용한 비관적 락(PessimisticLock)

2.2.1 @Lock 어노테이션 사용법

public interface UserRepository extends JpaRepository<UserEntity, Long> {

    @Lock(LockModeType.PESSIMISTIC_WRITE)
    Optional<UserEntity> findByIdForUpdate(Long id);
    
}
  • LockModType의 종류
    • PESSIMISTIC_READ : 다른 트랜잭션에서 읽기만 가능
    • PESSIMISTIC_WRITE : 다른 트랜잭션에서 읽기도 못하고 쓰기도 못함
    • PESSIMISTIC_FORCE_INCREMENT : 다른 트랜잭션에서 읽기도 못하고 쓰기도 못함 + 추가적으로 버저닝을 수행한다.

 

 

# 참고자료

 

728x90