만약 옷을 판매하는 쇼핑몰에서 고객이 옷을 구매했다고 생각해보자, 고객은 옷을 구매하였고 배송지를 변경하고자 하고 쇼핑몰 운영자는 배송을 준비하기 위해서 배송 준비 중 상태로 변경하고자 한다. 이렇게 될 경우 운영자는 기존 배송지 정보를 이용해서 배송 상태로 변경했는데 그 사이 고객은 배송지 정보를 변경하여 애그리거트의 일관성이 깨질 수 있다. 이러한 문제를 해결하기 위해서 선점잠금과 비선점 잠금 2가지 방식으로 문제를 해결할 수 있다.
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select m from Member m where m.id = :id")
Optional<Member> findByIdForUpdate(@Param("id") MemberId memberId);
Map<String, Object> hints = nwe HashMap<>();
hints.put("javax.persistence.lock.timeout", 2000);
Order order = entityManager.find(
Order.class, orderNo, LockModeType.PESSIMISTIC_WRITE, hints);
선점 방식으로 모든 문제를 해결 할 수 없기 때문에 비선점 방식도 고려해볼 수 있다. 이 때 비선점 방식을 고려해볼 수 있다. 비선점 잠금 방식은 동시에 접근하는 것을 막는 대신 변경한 데이터를 실제 DBMS에 반영하는 시점에 변경 가능 여부를 확인하는 방식이다.
JPA는 버전을 이용한 비선점 잠금 기능을 지원한다. @Version 애너테이션을 붙이고 매핑되는 테이블에 버전을 저장할 컬럼을 추가하면 된다.
@Entity
@Table(name = "purchase_order")
@Access(AccessType.FIELD)
public class Order {
@EmbeddedId
private OrderNo number;
@Version
Private long version
...
update purchase_order SET ...생략, version = versino + 1
WHERE number = ? and version = 10