JPQL UPDATE와 비관적/낙관적 락 차이: 동시성 문제 해결 전략
AI Store에서 AI코딩으로 만들어진 앱을 만나보세요!
지금 바로 방문하기

JPQL UPDATE와 비관적 락, 낙관적 락 차이: 동시성 문제를 실무처럼 고민하기

분야 프로그래밍/소프트웨어 개발

대상자

  • Spring Data JPA를 사용하는 개발자
  • 동시성 처리와 데이터 정합성 문제를 고민하는 개발자
  • 낙관적 락과 비관적 락 전략 선택에 어려움을 겪는 개발자

핵심 요약

  • JPQL UPDATE는 DB 레벨에서 비관적 락(Pessimistic Lock)을 자동으로 적용*합니다.
  • @Modifying(clearAutomatically = true)는 영속성 컨텍스트를 초기화해 동시성 문제를 방지*합니다.
  • 비관적 락은 락을 즉시 적용해 정합성 보장*하지만 성능 저하가 발생합니다.
  • 낙관적 락은 버전 필드(@Version) 기반 충돌 검사를 통해 성능 우위*를 제공합니다.

섹션별 세부 요약

1. 락 전략 비교

  • 비관적 락 (Pessimistic Lock)
  • JPQL UPDATE나 SELECT FOR UPDATE로 DB 레벨에서 락 적용
  • 동시 수정 방지, 데이터 정합성 강력 보장
  • 성능 저하, 블로킹 발생 가능성
  • 낙관적 락 (Optimistic Lock)
  • @Version 필드를 기반으로 충돌 검사
  • 성능 우수, 락 없이 동시성 처리
  • 충돌 시 예외 발생, 로직 복잡도 증가
  • 락 전략 선택 기준
  • 데이터 변경 빈도, 트래픽 패턴, 동시성 중요도에 따라 선택

2. JPQL UPDATE의 특성

  • @Modifying 어노테이션과 함께 사용 시 쓰기 락(write lock) 자동 적용
  • clearAutomatically = true 필수: 영속성 컨텍스트 초기화로 조회 결과 불일치 방지
  • 한 번의 쿼리로 리뷰 수, 평점 등 복합 필드 갱신 가능
  • 예시 코드

```java

@Modifying(clearAutomatically = true)

@Query("""

UPDATE Book b

SET

b.reviewCount = (SELECT COUNT(r) FROM Review r WHERE r.book.id = :bookId),

b.rating = (SELECT COALESCE(AVG(r.rating), 0) FROM Review r WHERE r.book.id = :bookId)

WHERE b.id = :bookId

""")

void recalcStats(@Param("bookId") UUID bookId);

```

3. 실무 적용 고려사항

  • 단순 ++ 연산은 동시성 충돌로 인해 중복 업데이트 또는 값 손실 발생 가능성
  • 쿼리 기반 갱신락 전략 선택이 필수적 (예: 리뷰 생성 시 Book 엔티티 갱신)
  • 비관적 락 대안: LockModeType.PESSIMISTIC_WRITE로 JPQL 없이 락 적용

```java

Book book = em.find(Book.class, bookId, LockModeType.PESSIMISTIC_WRITE);

```

  • 참고 자료:
  • Hibernate User Guide - Locking
  • Spring Data JPA - Modifying Queries
  • Baeldung - Optimistic Locking in JPA

결론

  • 데이터 특성과 트래픽 패턴에 따라 적절한 락 전략 선택이 필수적
  • @Modifying(clearAutomatically = true)는 JPQL UPDATE 시 동시성 문제를 방지하는 핵심 옵션
  • 비관적 락은 정합성 보장에 유리하지만 성능 저하 발생, 낙관적 락은 성능 우위를 가지나 충돌 시 로직 복잡도 증가
  • 실무에서는 락 전략과 쿼리 기반 갱신을 병행해 동시성 문제를 최소화하는 것이 권장됨