Spring/JPA

OSIV 관련 정리

Jemlog 2021. 12. 30. 01:14
  • 기본적으로 트랜젝션과 영속성 컨텍스트는 범위를 같게 한다.
  • 순서는 → 스프링 트랜젝션 AOP 동작 → 트랜젝션 내 메서드 호출 → 트랜젝션 커밋 직전 영속성 컨텍스트 플러시 → 트랜젝션 종료 → 그 이후 엔티티는 준영속 상태
  • 여러 쓰레드가 하나의 엔티티 매니져에 접근 할 수 있지만, 쓰레드마다 트랜젝션이 별개로 할당되기 때문에 영속성 컨텍스트도 따로 할당된다.
  • 근데 이 상태에서는 변경 감지나 지연로딩을 사용하지 못한다. 이것들은 모두 영속성 컨텍스트가 살아있을때만 가능하다. 지연로딩은 트랜젝션과 상관없이 영속성 컨텍스트만 살아있으면 된다.
  • 지연로딩은 즉시로딩의 N+1 문제를 해결해준다. 하지만 지연로딩 자체도 DTO로 변환할때 N+1문제를 가질 수 있다. 
  • 즉시로딩에서의 N+1 문제 과정 -> JPQL은 문자 그대로 쿼리를 실행하기 때문에 select m from Member m을 할 시 연관관계는 고려하지 않는다. -> 막상 가져온 후 즉시로딩이 걸려있는 연관관계가 있다면, 가져온 엔티티의 개수만큼(N개 만큼) 쿼리를 DB에 추가적으로 보내게 된다. 
  • 스프링 OSIV를 키면 해결된다. 스프링 OSIV는 영속성 컨텍스트의 생존 범위가 조금 다르다. 우리가 일반적으로 쓰는 범위다.
  • 순서는 → 요청이 들어오면 영속성 컨텍스트 생성 → 트랜젝션 발생하면 해당 트랜젝션이 영속성 컨텍스트를 찾아간다 → 트랜젝션이 끝날때 영속성 컨텍스트도 flush를 하지만 종료되지는 않는다. → 나중에 응답까지 나가면 그때서야 flush 없이 clear를 통해서 끝이 난다.
  • 요청부터 응답까지 하나의 영속성 컨텍스트만 사용하기에 트랜젝션간에 영속성 컨텍스트 공유가 가능하다. 롤백할때 문제 생길 수 있다.
  • 실시간 API가 중요한 애플리케이션에서는 트랜젝션이 시작되자마자 데이터베이스 커넥션을 물기 때문에 응답이 나갈때까지 데이터베이스 커넥션을 물고 있다. 커넥션이 마를 수 있기 때문에 장시간 사용을 피해야 한다. 
  • open-in-view를 끄고, 프레젠테이션을 위한 쿼리를 담당하는 서비스를 하나 또 만들어서, 지연로딩 엔티티를 활성화 시키는 것도 방법이다.