[Spring JPA] JPA 책 정독(JPA 기본, 영속성 컨텍스트) - (1)

insukL·2024년 2월 13일
0

JPA 책 정독

목록 보기
1/1
post-thumbnail

JPA를 공부할 맘이 생기면 보통 '자바 ORM 표준 JPA 프로그래밍'이 가장 유명하고 이를 구매하게 됩니다. 저도 자연스레 책을 샀지만, 매번 프로젝트할 때마다 책 내용을 다시 정리하고 에러를 보면서 이런 사례가 있었지 하곤 합니다. 그래서 진짜 마지막이란 마음으로 정리하고 다시 볼 필요가 있으면 시리즈 정독을 하면 좋겠다 싶어서 만드는 글입니다.

JPA란 무엇인가?

  • Java 진영의 ORM 기술 표준
    • 하이버네이트 기반의 자바 ORM로 기존의 엔티티 빈이라는 ORM 기술보다 가볍고 실용적
  • 어플리케이션과 JDBC 사이에서 동작함

ORM이란?

데이터베이스와 객체 사이의 패러다임 불일치 문제를 개발자 대신 해결해주는 프레임워크
패러다임에 대한 고민을 빼고 각각의 모델링에 집중할 수 있게 도와줌

  • 데이터 접근 추상화와 벤더 독립성 제공
    • 데이터베이스별 방언 클래스를 제공하여, 특정 데이터베이스에 의존적인 구문은 방언을 통해 처리함

ORM에 대한 궁금증과 오해

  1. SQL이나 데이터베이스에 대해서 잘 모르고 써도 괜찮은가?
    • 아니요. 데이터베이스를 객체지향적으로 개발하는 것을 도와주는 도구로 데이터는 관계형으로 저장됨. 그래서 양측의 매핑이 올바르게 이뤄질 수 있도록 양측 모두에 대한 이해가 요구됨.
  2. 성능이 느린가요?
    • 다양한 성능 최적화 기능을 제공하고 있으며, 잘 이해하고 사용하면 SQL을 직접 사용하는 것보다 좋을 수 있음. 그리고 SQL을 직접 작성하는 기능도 지원함
  3. 복잡한 쿼리는 어떻게 처리하나요?
    • JPA의 경우엔 복잡한 쿼리보단 실시간 처리용 쿼리에 최적화 된 경향이 있음. 그래서 너무 복잡한 경우에는 네이티브 SQL을 사용하거나 SQL 매퍼 프레임워크를 혼용하는 것도 좋은 방법임.

영속성 관리

엔티티 매니저

  • 엔티티와 관련된 작업을 진행하는 관리자 객체
  • 엔티티 매니저 팩토리를 생성하는 비용은 크나, 매니저 생성 비용이 적으므로 1개의 팩토리를 두고 매니저를 생성하여 사용
  • 엔티티 매니저는 여러 스레드에서 동시에 접근하면 동시성 문제가 생기므로 절대 공유되선 안됨

영속성 컨텍스트

  • 엔티티를 보관하고 관리하는 환경
  • 엔티티 매니저를 생성할 때, 하나 만들어짐

엔티티의 생명주기

  • 비영속 : 영속성 컨텍스트와 관계 없는 상태
    • 영속성 컨텍스트나 데이터베이스와 관계 없는 상태
  • 영속 : 영속성 컨텍스트에 저장된 상태
    • 엔티티 컨텍스트에 의해 관리되는 상태
  • 준영속 : 영속성 컨텍스트에 저장되었다가 분리된 상태
    • 영속 상태의 엔티티를 더 이상 영속성 컨텍스트가 관리하지 않으면 준영속 상태가 됨
  • 삭제 : 영속성 컨텍스트에서 삭제된 상태

영속성 컨텍스트의 특징

  • 영속성 컨텍스트는 엔티티 식별자 값( @Id로 매핑된 필드 )으로 구분
  • 영속성 컨텍스트 내에서의 변화는 flush를 통해 데이터베이스에 반영됨
  • 영속성 컨텍스트를 통해 아래의 이점을 얻을 수 있음
    • 1차 캐시
      • 영속성 컨텍스트 내에 1차 캐싱을 하고 있으며, 엔티티 조회 시 먼저 1차 캐싱에서 찾음
      • 1차 캐싱에 없는 경우엔 데이터베이스에서 조회해서 1차 캐싱에 저장함
    • 동일성 보장
      • 동일한 식별자의 엔티티는 1차 캐싱에서 반환하므로, 동일성을 보장함
    • 트랜잭션을 지원하는 쓰기 지연
      • 엔티티 매니저는 트랜잭션을 커밋하기 직전까지 데이터베이스에 저장하지 않고, 내부 쿼리 저장소에 저장해두었다가 커밋 시 데이터베이스로 쿼리를 보냄
      • 데이터베이스 동기화를 진행한 후 트랜잭션을 커밋함
      • 쿼리를 모아서 보내고 커밋을 진행하나, 매번 쿼리를 보낸 뒤 트랜잭션을 커밋하나 결과가 동일하기 때문에 해당 기능이 지원 가능
    • 변경 감지
      • 수정 쿼리를 보낼 시, 같은 엔티티에 대해서 합쳐서 보낼 수 있음
      • 영속성 컨텍스트는 최초 상태를 복사하여 저장하는데, 이를 스냅샷이라고 함
      • flush가 호출되면 스냅샷과 현재의 엔티티를 비교하여 변경된 부분에 대해서만 쿼리를 생성함
      • 이런 기능을 지원하지만 다음의 이유로 JPA는 전체 교체가 기본 전략임
        • 모든 필드를 사용하면 수정 쿼리가 항상 동일하므로, 쿼리를 미리 생성해두고 재사용할 수 있음
        • 데이터베이스에서 동일한 쿼리에 대해서 파싱된 쿼리를 캐싱하므로 재사용할 수 있음
      • 필드가 너무 많거나 내용이 너무 크면 동적 쿼리 생성 전략을 선택하면 됨
        • 수정되는 컬럼이 30개 이상 정도 되면 @DynamicUpdate 어노테이션이 빠르다고 함
          • 근데 테이블에 컬럼이 30개 이상 정도 되면 잘못된 설계에 가까움
    • 지연 로딩

영속성 컨텍스트는 제 생각에 JPA 작동에 있어서 가장 근간이 되는 부분이라고 생각합니다. 엔티티를 어떻게 영속 상태로 만들고, 컨텍스트 내에서 관리할지 고민하게 되는데 이 부분을 짚어가면서 정리하면 좋을 것 같습니다.

플러시(flush)

  • 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 것
  • 플러시하는 방법은 3가지가 있음
    1. 직접 호출
      • 거의 사용하지 않음
    2. 트랜잭션 커밋 시 자동 호출
      • 트랜잭션만 커밋되면 변경 사항이 저장되지 않으므로 자동 호출됨
    3. JPQL 쿼리 실행 시 자동 호출
      • 쿼리 내에서 반영되지 않은 영속 상태의 엔티티 사용을 방지하기 위해 이전에 영속 상태로 전환한 엔티티에 대해 flush를 실행함

JPA가 데이터 계층에 관여되는 만큼 성능에 대한 고민이 빠질 수 없습니다. 그래서 기본적인 동작 방식과 그 흐름에 따른 사고가 뒷받침 되고 비교가 필요하다고 생각됩니다.

profile
데이터를 소중히 여기는 개발자가 되고 싶습니다

0개의 댓글