JPA 스터디, #1

박주진·2021년 9월 14일
0

JPA 스터디

목록 보기
1/3

아래 내용은 김영한 님의 자바 ORM 표준 JPA 프로그래밍의 내용에 기반하여 정리한 글입니다.

JPA가 나온 배경

현시점에서 객체를 영구 보관하는 방법중 가장 현실적인 대안은 관계형 데이터베이스이다. 하지만 관계형 데이터베이스와 객체지향간에는 패러다임 불일치가 존재한다. 그래서 객체를 객체답게 모델링 할수록 두 패러다임의 불일치를 해결하기 위해 너무 많은 시간과 코드가 필요하다. 그러다보니 결국엔 애플리케이션은 데이터베이스 중심 즉 SQL 중심의 형태를 가지게 된다.

SQL를 직접 다룰 때 문제점

  • 많은 반복작업 (crud 쿼리 작성 및 변경)
  • 진정한 의미의 계층 분할 불가 (항상 직접 SQL를 봐야 실제로 사용되는 객체를 확인할 수 있음으로 데이터 접근 계층이 완전히 분리하기 힘듬)
  • 엔티티를 신뢰할 수 없다 (실제 실행되는 SQL를 보기전까지는 어떤 객체가 조회되는지 확인 불가)

구체적인 패러다임 불일치 문제

  • 상속 ( 상속(객체) vs 슈퍼타입 서브타입 관계(DB))
  • 연관관계 ( 참조(객체) vs 외래키(DB))
  • 객체 그래프 탐색 ( 참조(객체) vs SQL시 join 여부(DB))
  • 데이터 식별 방법 ( 동일성,동등성(객체) vs 기본키 값 (DB))

이러한 문제속에서 객체를 자바 컬렉션에서 사용하듯 DB에 저장할 수는 없을까에 대한 고민이 시작되었다. 그래서 탄생한게 JPA이다.

JPA란

  • 자바 진영의 ORM(object-relational mapping) 기술 표준.
  • 구체적인 구현 프레임워크에는 하이버네이트, EclipseLink 등이 있으나 하이버네이트가 가장 많이 사용된다.

ORM이란

  • 객체와 테이블을 매핑해서 패러다임의 불일치 문제를 해결해주는 프레임워크.
  • 자동으로 SQL 생성은 물론 패러다임 불이치 문제를 해결해주어 개발자는 관계형 데이터베이스를 사용해도 객체지향적으로 어플리케이션 개발할 수 있다.

왜 JPA를 사용해야 할까?

  • 생산성 (지루한 반복적인 CRUD SQL를 자동으로 생성해줌)
  • 유지보수 (SQL에 의존적이지 않게됨으로써 엔티티 변경과 같은 변경이 일어날때 유지보수 해야할 코드가 줄어듬)
  • 패러다임 불일치 해결 (위에 언급한 불일치 문제를 해결해줌으로써 객체지향적으로 어플리케이션 개발 가능)
  • 성능 (1차캐시, 쓰기지연, 즉시/지연로딩 등 다양한 최적화 지원)
  • 데이터 접근 추상화와 벤더 독립성 (데이터베이스와 어플리케이션 사이에 추상화된 데이터접근 계층을 제공해 특정 데이터베이스에 종속되지 않게해줌)
  • 표준 (다른 구현 기술로 손쉽게 변경 가능)

영속성 관리

엔티티 메니저

  • 엔티티를 저장,수정,삭제, 조회 등의 엔티티 관련 일을 처리하는 것.
  • 엔티티를 저장하는 가상의 데이터베이스,
  • 엔티티 팩토리를 통해 생성(팩토리는 데이터베이스당 하나이며 비용이 비싸 전체 어플리케이션에서 공유)
  • 동시성 문제가 있어 엔티티 매니저는 각 쓰레드당 하나가 할당됨.
  • 데이터베이스 연결이 필요한 시점까지는 데이터베이스 커넥션을 획득하지 않는다.

영속성 컨텍스트

  • 엔티티를 영구 저장하는 환경으로 엔티티 매니저는 엔티티를 영속성 컨텍스트에 보관 및 관리한다.
  • 엔티티 매니저 생성시 한개가 생성되고 엔티티 매니저에 의해 접근 및 관리된다.
  • 보통 한 트랙잰션 단위로 유지된다.
  • 여러 엔티티 매니저가 동일한 영속성 컨텍스트에 접근이 가능하다.

엔티티 생명주기

  • 비영속 (영속성 컨테스트와 관계가 없는 상태)
  • 영속(영속성 컨텍스트에 저장되어 엔티티가 매니저에 의해 관리되는 상태)
entityManger.persist(객체)
  • 준영속(영속성 컨테스트에 저장되었다가 분리된 상태)
entityManger.close() 영속성 컨텍스트 닫기
or
entityManger.clear() 영속성 컨텍스트를 초기화
or
entityManger.detach(객체) 영속성 컨텍스트에서 분리
  • 삭제(엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제된 상태)
entityManger.remove(객체)

영속선 컨텍스트를 왜 필요할까?

아래와 같은 이점이 있어 사용한다.

  • 1차캐시

    • 메모리에 존재하는 1차캐시가 있어 엔티티 조회시 데이터베이스 조회전 캐시에서 먼저 조회한다.
    • 영속성 컨텍스트가 사라짐과 동시에 같이 사라져 사실상 큰 성능에 이점은 없음.(한 트랙잭션 단위로 유효하다고 보면 될듯)
  • 동일성

    • 1차캐시에 존재하는 특정 엔티티를 반복하여 호출하여도 동일한 인스턴스가 반환된다.
    • 반복 가능한 읽기(REPEATABLE READ) 등급의 트랜잭션 격리 수준을 어플리케이션 차원에서 보장.
  • 쓰기지연

    • 엔티티 등록시

      • 엔티티 매니저를 통해 엔티티를 영속화 하면 엔티티 매니저는 엔티티를 분석해 insert query를 생성해 쓰기지연 SQL저장소에 저장한다.
      • 그후 transaction 커밋하는 순간 쓰기지연 SQL 저장소 모아둔 쿼리를 데이터베이스에 보낸다(flush)
      • hibernate.jdbc.batch_size 설정을 통해 쌓인 쿼리를 한방에 배치 쿼리로 보낼 수 있다.
      • 하지만 엔티티의 아이디를 @GeneratedValue(strategy = GenerationType.IDENTITY)로 설정한 것들은 batch insert가 작동하지 않고 영속성과 동시에 데이터베이스에 insert query가 보내진다. 자세한링크
    • 엔티티 수정

      • flush 시점에 엔티티의 snap shot(최초상태)과 실제 엔티티와 비교해서 변경된 부분을 update query를 만들어 쓰기지연 저장소에 보낸다. 그리고 이게 다시 데이터베이스에 보내진다.
      • 이런 변경감지 기능을 dirty read라고 부른다.
      • update query는 변경된 부분만 생성되는게 아니라 모든 필드를 update query에 포함시킨다.
        • 장점은 항상 수정 쿼리가 같아 미리 생성해두고 재사용 가능, 데이터베이스에서는 동일한 쿼리가 주어지면 이미 파싱된 쿼리를 재사용 가능
        • 단점은 데이터 전송량 증가
        • @org.hibernate.annotations.DynamicUpdate 애노테이션을 활용하면 UPDATE SQL을 생성하는 전략을 변경해 수정되는 부분만 update query 작성하게 할 수 있다.
        • 보통은 컬럼이 30개 이상이 되면 기본방법이 느려질수 있지만 직접 테스트 해보고 업데이트가 너무 느리면 그때 수정하는 방향을 권장한다.
      • 변경 감지는 영속성 컨텍스트가 관리하는 영속 상태의 엔티티에만 적용
    • 엔티티 삭제

      • 엔티티 삭제또한 삭제 쿼리가 쓰기 지연저장소에 등록되고 flush 호출시 쿼리가 데이터베이스에 전달된다.
  • 지연로딩

    • 연관된 객체를 처음부터 데이터베이스에서 조회하는 것이 아니라 실제 사용하는 시점에 데이터베이스에서 조회하도록 하는 기능

flush

  • 영속성 컨텍스트의 변경을 데이터베이스에 반영하는 것
  • 변경감지를 통해 수정 쿼리 생성 -> 쓰기지연 SQL 저장소 쿼리 데이터베이스 전송
  • FlushModeType.AUTO (기본), FlushModeType.COMMIT(커밋시에에만 flush) 두가지 모드 존재
flush를 호출하느 3가지 방법
  • 직접 호출
  • transaction commit 시 자동호출
  • JPQL쿼리 실행직전 자동호출

준영속

  • 영속성 컨텍스트가 관리하는 영속 상태의 엔티티가 영속성 컨텍스트에서 분리되는 것
  • 영속성 컨텍스트가 제공하는 기능을 사용할 수 없다
  • 준영속 상태로 만드는 법
    • detach(entitty) 해당 엔티티에 관한 모든 정보가 영속성 컨텍스트에서 사라짐
    • clear() 영속성 컨텍스트를 초기화 하여 담겨있는 모든 엔티티를 준영속 상태가 된다.
    • close() 영속성 컨텍스트를 종료하여 담겨있는 모든 엔티티를 준영속 상태가 된다.
  • 특징
    • 어떠한 영속성 컨텍스트가 제공하는 기능을 작동하지 않음으로 비영속성에 가깝다.
    • 이미 한 영속상태였으므로 식별자는 존재한다.
  • merge는 save or update 기능을 수행해 준영속 또는 비영속 상태의 엔티티를 영속상태로 변경해준다.

0개의 댓글