🖤 Book Study/자바 ORM 표준 JPA 프로그래밍

15장. 고급주제와 성능최적화

드림살구잼 2023. 7. 18. 22:15

15.1 예외 처리 (JPA를 사용할 때 발생하는 다양한 예외와 예외에 따른 주의점)

  • JPA 표준 예외들은 javax.persistence.PersistenceExpection의 자식 클래스이며, 이 예외 클래스는 RuntimeException의 자식이다. 따라서 JPA예외는 모두 언체크 예외이다. 
  • JPA 표준 예외는 크게 "트랜잭션 롤백을 표시하는 예외"와 "트랜잭션 롤백을 표시하지 않는 예외"로 나뉜다. 
  • "트랜잭션 롤백을 표시하는 예외"는 심각한 예외이므로 복구해서는 안되며, 강제로 커밋해도 대신에 예외가 발생한다. 반면 "트랜잭션 롤백을 표시하지 않는 예외"는 심각한 예외가 아니므로 개발자가 트랜잭션을 커밋할지 롤백할지를 판단하면 된다. 

트랜잭션 롤백 시 주의사항

- 트랜잭션 롤백은 데이터베이스의 반영사항만 롤백하는 것이며, 수정한 자바 객체까지 원상태로 복구해주지는 않는다. 

예) 데이터베이스의 데이터는 복구되도, 객체는 수정된 상태로 영속성 컨텍스트에 남아있다. 

따라서 트랜잭션이 롤백된 영속성 컨텍스트를 그대로 사용하는것은 위험

-> 새로운 영속성 컨테스를 생성하여 사용 or EntitiyManager.clear()를 호출하여 영속성컨텍스트를 초기화 후 사용

 

 

15.2 엔티티 비교 (엔티티를 비교할 때 주의점과 해결방법)

  • 영속성 컨텍스트 내부에는 엔티티 인스턴스를 보관하기 위한 1차 캐시가 있으며, 1차 캐시는 영속성 컨텍스트와 생명주기를 같이 한다. 
  • 영속성 컨텍스트를 통해 데이터를 저장하거나 조회하면 1차 캐시에 엔티티가 저장된다. 이 1차 캐시로 인해 변경 감지 기능이 동작하며, 데이터베이스를 통하지 않고 데이터를 바로 조회할 수도 있는 것이다. 
  • 1차 캐시의 가장 큰 장점 = "애플리케이션 수준의 반복 가능한 읽기" : 같은 영속성 컨텍스트에서 엔티티를 조회하면 항상 같은 엔티티 인스턴스를 반환한다. 단순히 동등성(equals) 비교 수준이 아닌 정말 주소값이 같은 인스턴스를 반환한다.

- 영속성 컨텍스트가 같을 때 엔티티 비교

  • 동일성 (identical) : == 비교가 같다.
  • 동등성 (equinalent) : equlas() 비교가 같다.
  • 데이터베이스의 동등성 : @Id인 데이터베이스 식별자가 같다.

 

- 영속성 컨텍스트가 다를 때 엔티티 비교

  • 동일성 (identical) : == 비교가 실패한다.
  • 동등성 (equinalent) : equlas() 비교가 만족한다. 단 equals()를 구현해야 한다. 보통 비즈니스 키로 구현한다.
  • 데이터베이스의 동등성 : @Id인 데이터베이스 식별자가 같다.

 

 

15.3 프록시 심화 주제 (프록시로 인해 발생하는 다양한 문제점과 해결방법) -??

  • 영속성 컨텍스트와 프록시
  • 프록시 타입 비교
  • 프록시 동등성 비교
  • 상속관계와 프록시

뭔지 잘 모르겠다 나중에 다시보기

 

 

 

15.4 성능 최적화

- N+1 문제 : 한번에 많은 SQL이 실행됨.

  • 즉시로딩과 N+1 (필요하지 않은 엔티티를 로딩해야하는 상황이 자주 발생할 수 있으며, 성능 최적화가 어렵다는 단점이 잇다)
  • 지연로딩과 N+1 (모두 지연로딩으로 설정하고 성능최적화가 필요한 곳에는 JPQL페치 조인을 사용하는걸 추천)

 

  • 페치 조인 사용 : N+1 문제를 해결하는 가장 일반적인 방법. 페치 조인은 SQL조인을 사용해서 연관된 엔티티를 함꼐 조회하므로 문제가 발생하지 않는다.
  • 하이버네이트 @BatchSize : @org.hibernate.annotations.BatchSize(size = 숫자) 어노테이션을 사용하면 연관된 엔티티를 조회할 때 지정한 size만큼 SQL의 IN 절을 사용해서 조회한다. 예) 조회한 회원이 10명이고 size=5로 지정한 경우, 2번의 SQL만 추가로 실행된다.
  • 하이버네이트 @Fetch(FetchMode.SUBSELECT) : @org.hibernate.annotaitons.Fetch(FetchMode.SUBSELECT) 어노테이션을 사용하면 연관된 데이터를 조회할 때 서브쿼리를 사용해서 N+1문제를 해결한다.

- 읽기 전용 쿼리의 성능 최적화 : 엔티티를 단순히 조회만 하면 영속성 컨텍스트에 스냅샷을 유지할 필요도 없고 영속성 컨텍스트를 플러시할 필요도 없다. 

- 배치 처리 : 수백만 건의 데이터를 처리해야하는 배치 처리 상황에서, 엔티티를 계속 조회하면 영속성 컨텍스트에 아주 많은 엔티티가 쌓이면서 메모리 부족 오류가 발생한다. 따라서 배치 처리는 적절한 단위로 엔티티를 데이터베이스에 플러시하고, 영속성 컨텍스트를 초기화 해야한다. 또한 2차 캐시를 사용하고 있다면 2차 캐시에 엔티티를 보관하지 않도록 주의해야한다. (왜지? 16장에서 찾아보기)

  • JPA 등록 배치 처리
  • JPA 수정 배치 처리 : 페이징 처리(데이터베이스에 페이징 기능을 사용) 방법 / 커서(데이터베이스가 지원하는 커서cursor 기능을 사용) 방법
  • 하이버네이트의 scroll(이라는 이름으로 JDBC 커서를 지원한다)을 사용
  • 하이버네이트의 무상태 세션 사용 (영속성 컨텍스트를 만들지 않고, 2차 캐시도 사용하지 않는다.)

- SQL 쿼리 힌트 사용 : JPA는 DB SQL힌트 기능을 제공하지 않아 하이버네이트 쿼리가 제공하는 addQueryHint() 메서드를 사용한다.

- 트랜잭션을 지원하는 쓰기 지연을 통한 성능 최적화 : 트랜잭션을 지원하는 쓰기 지연SQL 배치 기능을 사용할 수 있다.