실전! 스프링 데이터 JPA - 인프런 | 강의
스프링 데이터 JPA는 기존의 한계를 넘어 마치 마법처럼 리포지토리에 구현 클래스 없이 인터페이스만으로 개발을 완료할 수 있습니다. 그리고 반복 개발해온 기본 CRUD 기능도 모두 제공합니다.
www.inflearn.com
Spring Data JPA - Reference Documentation
Example 119. Using @Transactional at query methods @Transactional(readOnly = true) interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") void del
docs.spring.io
JPA의 낙관적 잠금(Optimistic Lock), 비관적 잠금(Pessimistic Lock)
요청이 많은 서버에서 여러 트랜잭션이 동시에 같은 데이터에 업데이트를 발생시킬 경우에 일부 요청이 유실되는 경우가 발생하여 장애로 이어질 수 있습니다. 이를 위해 동시 읽기/업데이트
velog.io
JPA에서 Optimistic Lock과 Pessimistic Lock
낙관적 락 (Optimistic Lock) 트랜잭션 대부분 충돌이 발생하지 않는다고 가정하는 방법으로써 어플리케이션이 제공하는 락 방식입니다. 그러므로 읽는 시점에 Lock을 사용하지 않기 때문에 데이터를
skasha.tistory.com
JPA 잠금(Lock) 이해하기
JPA(Hibernate:하이버네이트)에 의한 잠금(Lock:락) 사용중에 생각하고 있던바와 동작이 좀 다른 부분이 있어서 전반적으로 정리해 보았습니다. 잠금(Lock)의 종류 낙관적 잠금(Optimisstic Lock) 낙관적 잠
reiphiel.tistory.com
HINT
JPA 힌트는 SQL 힌트가 아니라 JPA 구현체에게 제공하는 힌트이다.
JPA는 쿼리 최적화를 위한 SQL힌트는 제공하고 있지 않으며 SQL힌트를 사용하기 위해서는 NativeQuery를 사용해야 한다.
@QueryHints 어노테이션과 @QueryHint 어노테이션을 사용하여 구현한다.
- org.springframework.data.jpa.repository.QueryHints
- javax.persistence.QueryHint
readOnly
기본적으로 JPA는 영속성컨텍스트의 변경감지를 통해 CUD 쿼리를 처리한다.
이를 위해서 영속성 컨텍스트는 항상 원본 엔티티 객체와 관리를 위한 사본 엔티티 객체를 총 두 개의 객체를 메모리에 저장한다.
엔티티를 읽기만 할 때는 원본객체가 필요없기 때문에 readOnly 힌트를 통해 원본 객체를 저장하지 않도록하여 성능 최적화를 할 수 있다.
@QueryHints(value = @QueryHint(name = "org.hibernate.readOnly", value = "true"))
Member findReadOnlyByUsername(String username);
forCounting 속성
반환타입으로 Page인터페이스를 적용할 때 페이징을 위해 추가로 호출하는 count 쿼리에도 힌트를 적용한다. (default : true)
@QueryHints(value = { @QueryHint(name = "org.hibernate.readOnly", value = "true")},
forCounting = true)
Page<Member> findByUsername(String name, Pagable pageable);
LOCK
JPA의 잠금에는 낙관적 잠금(Optimistic Lock)과 비관적 잠금(Pessimistic Lock)이 있다.
낙관적 잠금(Optimistic Lock)
- 어플리케이션 단에서 제공하는 락 방식으로 데이터 갱신시 충돌이 발생하지 않을 것이라 가정하고 잠금을 거는 기법이다.
- DB Lock을 사용하지 않기 때문에 트랜잭션 커밋 전까지 충돌 여부를 알 수 없고 갱신시점에 데이터의 변경여부를 확인해야한다.
- 디비에 락을 걸기보다는 충돌 방지(Conflict detection)에 가깝다고 볼 수 있다.
@Version
- JPA에서 낙관적 락을 사용하려면 엔티티 내부에 @Version 어노테이션을 사용한 필드를 추가하여 버전 관리를 구현하면 된다.
- 엔티티에는 하나의 버전 필드만 있어야하며 지원되는 타입은 long, Long, int, Integer, short, Short, TimeStamp 이다.
- 버전필드는 엔티티를 수정 할 때 자동으로 증가하며, 조회 시점과 버전이 다른 경우 OptimisticLockException이 발생한다.
낙관적 잠금 종류
- NONE
엔티티에 버전 필드이 존재하면 별도의 옵션을 적용하지 않아도 암시적으로 낙관적 잠금이 적용된다. - OPTIMISTIC (Read)
엔티티 수정 시에만 발생하는 낙관적 잠금을 읽기 시에도 발생하도록 설정한다.
이를 통해 dirty read와 non-repeatable read를 방지한다. - OPTIMISTIC_FORCE_INCREMENT (Write)
낙관적 잠금을 사용하면서 버전 정보를 강제로 증가시킨다.
기본 JPA에서의 명시적 낙관적 잠금 사용방법
// 엔티티를 영속성 컨텍스트로 부터 찾거나 select하면서 동시에 잠금을 거는 경우 사용
entityManager.find(Member.class, memberId, LockModeType.OPTIMISTIC);
Member member = entityManager.find(Member.class, memberNo);
// 이미 영속성 컨텍스트에 담겨있는 엔터티를 대상으로 잠금을 걸때 사용
entityManager.lock(member, LockModeType.OPTIMISTIC);
Query객체의 setLockMode() 메서드를 이용한 방법
Query query = entityManager.createQuery("select m from Member m where m.id = :id");
query.setParameter("id", memberId);
query.setLockMode(LockModeType.OPTIMISTIC_INCREMENT);
query.getResultList()
@NamedQuery 어노테이션의 lockMode 속성을 이용한 방법
@NamedQuery(name="optimisticLock",
query="select m from Member m where m.id = :id",
lockMode = WRITE)
비관적 잠금(Pessimistic Lock)
- 트랜잭션 충돌이 발생한다고 가정하고 우선 락을 거는 방법이다.
비관적 잠금 종류
- LockModeType.PESSIMISTIC_WRITE (default)
배타적 잠금(Exclusive Lock)
다른 트랜잭션에서 READ, UPDATE, DELETE가 불가능하도록 설정한다. - LockModeType.PESSIMISTIC_READ
공유 잠금(Shared Lock)
다른 트랙잭션에서 READ 만 가능하도록 설정한다. - LockModeType.PESSINISTIC_FORCE_INCREMENT
PESSIMISTIC_WRITE와 유사하게 작동하지만 엔티티의 버전 필드를 추가로 증가시킨다.
Spring Data JPA에서의 비관적 잠금 사용방법
// JPA의 기본 동작은 select - update 이다
// 여러 쓰레드에서 동시에 하나의 값을 변경하게 되면 정합성을 보장하기 어렵기 때문에 비관적 잠금을 설정해줄 수 있다.
@Lock(LockModeType.PESSIMISTIC_WRITE)
List<Member> findByUsername(String name);
Exception
PessimisticLockException
- 공유잠금(Shared Lock) 또는 배타적잠금(Exclusive Lock) 둘중에 하나의 락만 획득 할 수 있다.
- 락을 획득하는데 실패하면 해당 예외가 발생한다.
LockTimeoutException
- 락을 대기하다 설정된 wait time이 초과되었을때 발생한다.
PersistenceException
- 영속성 문제가 발생하는 경우 발생하는 예외
Lock Scope
PessimisticLockScope.NORMAL (default)
- 해당 엔티티만 잠금을 설정한다.
- @Inheritance(strategy = InheritanceType.JOINED)와 같이 조인 상속을 사용하면 부모도 함께 잠금이 설정된다.
PessimisticLockScope.EXTENDED
- @ElementCollection, @OneToOne, @OneToMany 등 연관관계에 있는 엔티티도 함께 잠금이 설정된다.
'Spring Data JPA' 카테고리의 다른 글
Auditing (0) | 2022.12.20 |
---|---|
사용자 정의 레퍼지토리 (0) | 2022.12.18 |
엔티티 그래프 @EntityGraph (0) | 2022.12.18 |
벌크성 수정쿼리 @Modifying (0) | 2022.12.18 |
페이징과 정렬 (0) | 2022.12.18 |