기타

JPA Tips

v0o0v 2022. 12. 19. 17:00
  • 엔티티 매니저는 트랜잭션 별로 생성된다(스프링 기본). 엔티티 매니저는 영속성 컨텍스트를 가지고 있고 1차 캐시의 역할을 하게 된다. 이로 인해 애플리케이션 수준의 반복 가능한 읽기가 가능하다(DBMS의 Repeatable Read와 별개로). 이를 위해 엔티티매니저를 통해 읽기를 할 때 1차 캐시에 이미 해당 영속성 객체가 있다면 DB에서 조회하지 않고 이를 반환한다. 또한, JPQL을 통해 쿼리를 하면 영속성 컨텍스트를 확인하지 않고 바로 DB에서 가져오는데 가져온후에 영속성 컨텍스트에 이미 해당 객체가 있다면 DB에서 가져온 객체를 버리고 영속성 컨텍스트에 있는 값을 반환한다.
  • 영속성 컨텍스트에는 1차 캐시와 쓰기 지연 SQL 저장소가 있다. flush를 할 때 쓰기 지연 SQL에 있는 쿼리가 발생한다.
    • 변경 감지 기능 : JPA는 엔티티를 영속성 컨텍스트에 보관할 때 최초 상태를 복사해서 저장한다(스냅샵). 그리고 플러시 시점에 스냅샵과 엔티티를 비교해서 변경된 엔티티를 찾는다. 수정된 엔티티를 토대로 수정쿼리를 만들어서 쓰기 지연 SQL 저장소에 보낸다.
    • 2차 캐시
  • 연관 관계 설정
    • Many 쪽이 주인. @JoinCoumn 설정
    • One 쪽에는 mappedBy = "필드 이름" 으로 다른 쪽이 주인이라는 것을 명시
  • Cascade
  • 플러시는 아래와 같은 경우에 실행된다
    • flush() 실행
    • 트랜잭션 커밋 직전
      • 트랜잭션 커밋 전에 영속성 컨텍스트의 내용을 데이터베이스 반영한 후에 트랜잭션을 종료한다.
    • JPQL 쿼리 실행 직전(이건 옵션으로 안하게 할 수 있음. FlushModeType.COMMIT)
      • JPQL은 바로 디비로 쿼리를 날리기 때문에 그전에 영속성 컨텍스트의 변경 내용을 디비에 반영해야한다.
    • JPQL 벌크 연산
      • 벌크 연산은 영속성 컨텍스트에 반영이 되지 않는다(영속성 컨텍스트와 2차 캐시 무시). 따라서 벌크 연산을 수행한 직후에 영속성 컨텍스트를 초기화해서 불일치를 미연에 방지해야 한다.
  • JPQL 조인
    • 컬렉션과 조인 시 fetch를 쓰지 않으면 N+1 문제 발생. 꼭 페지 조인 활용.
    • 일대다 조인은 결과가 증가할 수 있다(JPA책 p.377) : 팀과맴버 조인 시 팀에 맴버가 여러명이면 맴버만큼 팀이 중복되는 row가 생성되기 때문. 그런데 JPA는 객체도 그만큼 중복해서 반환한다. 이를 막고자하면 select distinct 를 사용하면 조인 결과는 동일하지만 JPA가 자동으로 중복 객체는 제거하고 반환한다.
    • 페치 조인을 1대다에서 사용하면 페이징이 안되는 문제 발생(위에 말한 로우 결과 증가 문제로 팀의 페이징을 기대하지만 실제로는 맴버의 페이징이 되므로). hibernate.default_batch_fetch_size 옵션으로 IN 조회를 적극 활용하자. 억지로 페이징 하면 앱내에서 다 끌어와서 페이징 하게 되는데 이건 재앙이 될 수 있다. 사실 페이징을 하려면 필요한 필드들만 정리해서 DTO로 반환하는 것이 좋다
  • JPQL 경로 탐색의 종류(객체를 .으로 조회 m.team.name 등)
    • 상태 필드 : 그냥 값들. 특별히 신경쓸게 없다.
    • 단일 값 연관 경로( ...ToOne) : 묵시적 내부 조인이 발생한다. 계속 탐색 할 수 있고 문제가 없다.
    • 컬렉션 값 연관 경로(...ToMany) : 묵시적 내부 조인이 발생한다. 경로 탐색 시 Many를 만나면(컬렉션을 만나면) 여기까지가 경로 탐색의 끝이다. 조인을 통해 별칭을 다시 얻어서 해야 한다.
    • 묵시적 조인 보다는 명시적 조인을 사용하자
 

[JPA] 2차 캐시

안녕하세요. 오늘은 2차 캐시에 관해 정리한 내용을 작성해 보도록 하겠습니다. 그리고 2차 캐시에 관해 글을 작성하기에 앞서 우선 캐시와 JPA의 1차 캐시에 관해 잠시 설명해 보도록 하겠습니다

junghyungil.tistory.com