1 분 소요

Lock

한 임계 영역(critical section)에 여러 스레드 또는 프로세스가 접근하지 못하도록 하고싶을 때 Lock을 사용할 수 있다.
하지만 Lock을 여러 영역에 건다면 일을 처리할 수 있는 속도가 크게 떨어지기 때문에 무분별하게 사용하지는 않지만, 작업을 수행했을
때 정확성을 보장해야하는 영역이 있다면 Lock을 걸어주는게 좋다.

문제 상황

프로젝트를 진행하면서 DB 간 데이터를 동기화해주기 위해 Spring 애플리케이션 내에서 kafka를 통해 처리해주고 있었는데
이때 producer가 생성한 record는 (여러 consumer가 같은 topic을 바라보고 있다면) 여러 consumer에서 가져가기 때문에
consumer에서 record를 가져오는 즉시 DB에 반영해주는 서비스 로직을 작성했었고, 받아오는 데이터에 쇼핑몰 정보가 있었다.
새 쇼핑몰 정보가 들어온 경우 DB에 저장할 수 있게 Spring Data JPA에서 제공하는 save() 함수를 사용했고,
@Transactional을 적용했음에도 각 프로세스(또는 스레드)가 동시에 서비스 로직을 타고 있다면 반환하는 시점에 commit을 하므로
같은 쇼핑몰 정보가 저장되는 문제가 발생했었다.

Caused by: org.springframework.dao.IncorrectResultSizeDataAccessException: query did not return a unique result: 6

새 쇼핑몰이 아닌 경우 DB에 저장된 쇼핑몰 정보를 조회하게 되는데, 이때 Spring Data JPA에서 설정한 findByName()
사용하기 때문에 같은 쇼핑몰 이름으로 조회 시 여러 쇼핑몰을 조회하기 때문에 IncorrectResultSizeDataAccessException 예외가
발생하는 문제가 있었다. 즉, 새 쇼핑몰을 단 1번만 저장할 수 있도록 Lock을 사용해야만 했다.

적용

Spring Data JPA를 사용하는 경우 설정 방법은 매우 간단하다!
나같은 경우 findByName()을 설정해놓고 있었기 때문에 다음처럼 @Lock(LockModeType.PESSIMISTIC_WRITE)을 설정했다.

@Lock(LockModeType.PESSIMISTIC_WRITE)
Optional<Mall> findByName(String name);
  • LockModeType.PESSIMISTIC_WRITE
    • 일반적으로 사용
    • 다른 트랜잭션에서 읽기/쓰기 X
  • LockModeType.PESSIMISTIC_READ
    • 읽기만 할때 사용 (쓰기 X)
    • 다른 트랜잭션에서 읽기 가능

References

카테고리:

업데이트:

댓글남기기