JPA Hint
JPA Hint는 Java Persistence API에서 쿼리 실행 시 추가적인 힌트를 제공하여 동작을 커스터마이즈하거나 성능 최적화를 돕는 기능
JPA 쿼리의 동작 방식을 유연하게 제어하거나, 특정 데이터베이스 벤더에 특화된 설정을 추가하는 데 사용된다. (SQL 힌트가 아니라 JPA 구현체에게 제공하는 힌트) 지금까지 JPA Hint의 뜻과 사용 용도를 알아보았고, 이제부터는 사용 방법에 대해서 알아보자.
쿼리 힌트 사용
@QueryHints(value = @QueryHint(name = "org.hibernate.readOnly", value = "true"))
Member findReadOnlyByUsername(String username);
쿼리 힌트 사용 확인
@Test
public void queryHint() {
// given
Member member1 = memberRepository.save(new Member("member1", 10));
em.flush();
em.clear();
// when
Member findMember = memberRepository.findReadOnlyByUsername(member1.getUsername()); // 스냅샷 X
findMember.setUsername("member2");
em.flush(); // Update Query 실행 X
}
쿼리 힌트 Page 추가 예제
@QueryHints(
value = @QueryHint(name = "org.hibernate.readOnly", value = "true"),
forCounting = true)
Page<Member> findPageByUsername(String username, Pageable pageable);
- org.springframework.data.jpa.repository.QueryHints 어노테이션을 사용
- forCounting : 반환 타입으로 `Page` 인터페이스를 적용하면 추가로 호출하는 페이징을 위한 count 쿼리도 쿼리 힌트 적용(기본값 `true` )
JPA LOCK
JPA는 두 가지 잠금 방식(Optimistic Locking과 Pessimistic Locking)을 제공한다.
1. Pessimistic Locking (비관적 잠금)
@Lock(LockModeType.PESSIMISTIC_WRITE)
List<Member> findLockByUsername(String username);
- 데이터 충돌 가능성이 높을 것으로 가정하고, 데이터를 읽거나 수정할 때 다른 트랜잭션이 해당 데이터에 접근하지 못하도록 잠금을 건다.
- org.springframework.data.jpa.repository.Lock 어노테이션을 사용
잠금 모드
- PESSIMISTIC_READ: 다른 트랜잭션이 데이터를 읽을 수 있지만, 수정은 불가능.
- PESSIMISTIC_WRITE: 다른 트랜잭션이 데이터를 읽거나 수정할 수 없음.
- PESSIMISTIC_FORCE_INCREMENT: 데이터를 읽거나 수정할 때 버전 값도 강제로 증가.
Lock 사용 확인
@Test
public void queryHint() {
// given
Member member1 = memberRepository.save(new Member("member1", 10));
em.flush();
em.clear();
// when
Member findMember = memberRepository.findReadOnlyByUsername(member1.getUsername()); // 스냅샷 X
findMember.setUsername("member2");
em.flush(); // Update Query 실행 X
}
Lock 사용 결과
select
m1_0.member_id,
m1_0.age,
m1_0.team_id,
m1_0.username
from
member m1_0
where
m1_0.username=? for update
2. Optimistic Locking (낙관적 잠금)
@Entity
public class Member {
@Id
@GeneratedValue
private Long id;
@Version
private int version; // Optimistic Locking에 사용되는 필드
private String name;
}
- 데이터 충돌 가능성이 낮을 것으로 가정하고, 데이터를 수정할 때 충돌 여부를 검사한다.
- 데이터베이스에서 잠금을 유지하지 않으므로 성능이 높음.
- 읽기 작업이 많은 환경에 적합하다.
- 충돌이 발생하면 예외를 처리해야 하므로, 쓰기 작업이 많은 환경에서는 부적합하다.
작동 원리
// 데이터 수정 시 버전 값 확인
Member member = em.find(Member.class, memberId);
member.setName("New Name");
entityManager.merge(member);
// 버전 값이 일치하지 않으면 OptimisticLockException 발생
- 엔티티에 버전 필드(예: @Version)를 추가한다.
- 데이터를 읽을 때는 잠금을 걸지 않고, 데이터를 업데이트할 때 버전 값을 확인한다.
- 만약 버전 값이 변경되었다면 예외를 발생시켜 충돌을 처리힌다.
정리
- JPA에서 LOCK은 동시성 문제가 발생할 가능성이 있는 환경에서 데이터의 정합성을 보장하기 위해 사용된다.
- Optimistic Locking은 성능이 중요한 경우에 적합하며, 데이터 충돌 처리가 필요하다.
- Pessimistic Locking은 데이터 충돌을 사전에 방지하고자 할 때 유용하지만, 성능 저하와 데드락에 유의해야 한다.
'JPA' 카테고리의 다른 글
[Spring Data JPA] Auditing (0) | 2025.01.18 |
---|---|
[Spring Data JPA] 사용자 정의 리포지토리 구현 (0) | 2025.01.18 |
[Spring Data JPA] @EntityGraph (0) | 2025.01.17 |
[Spring Data JPA] 벌크성 수정 쿼리 (0) | 2025.01.17 |
[Spring Data JPA] 페이징과 정렬 (0) | 2025.01.16 |