선점(Pessimistic) 잠금
- 선점 잠금이란 먼저 애그리거트를 구한 스레드가 애그리거트 사용이 끝날때까지 다른 스레드가 해당 애그리거트를 수정하는 것을 막는 방식이다.
- 스레드1이 애그리거트를 수정하는 동안 블록킹이 되고 트랜잭션이 커밋되는 대기하고 있던 스레드2가 작동한다.
- 선점 잠금은 보통 DBMS가 제공하는 행 단위 잠금을 사용해서 구현한다.
- JPA의 EntityManager는 LockModeType을 인자로 받는 find() 메서드를 제공하는데,
- LockModeType.PESSIMISTIC를 값으로 전달하면 해당 엔티티와 매핑 된 테이블을 이용해서 선점 잠금 방식을 적용할 수 있다.
- JPA 프로바이더와 DBMS에 따라 잠금 모드의 구현이 다른데, 하이버네이트의 경우 PERSSIMISTIC_WRITE를 잠금 모드로 사용하면 'for update' 쿼리를 사용해서 선점 잠금을 구현한다.
선점 잠금과 교착 상태
- 만약 선점 잠금을 사용하는데 동시에 접근 잠금을 시도할때 두 스레드 모두 다 교착상태에 빠져 다음단계로 넘어가지 못할때가 있다.
- 이는 사용자가 많을때 발생할 가능성이 높다.
- 이를 방지하기 위해 잠금을 구할 때 최대 대기 시간을 지정해야 한다.
Map<String, Object> hints = new HashMap<>();
// 잠금을 구하는 대기 시간을 2초로 설정
hints.put("javax.persistence.lock.timeout", 2000);
Order order = entityManager.find(Order.class, orderNo, LockModeType.PESSIMISTIC_WRITE, hints);
- 지정된 시간 이내 잠금을 구하지 못하면 익셉션을 발생시킨다.
- 이 기능을 사용할 땐 사용중인 DBMS가 관련 기능을 지원하는지 확인이 필요하다.