JPA에 대해 - JPA란? & JPA 내부 동작 원리

쿠우·2022년 12월 27일
0

JPA의 소개

SQL중심적인 개발의 문제점

  • 무한반복 , 지루한 쿼리를 작성하는 코드
  • 중간에 추가하는 등 과정을 통해 sql에 의존적인 개발을 할 수 밖에 없다.
  • sql 매퍼를 개발자가 다 해주는데 객체답게 모델링 할수록 매핑작업이 늘어난다.

JPA? ORM? 사용의 이유?

  • JPA (Java Persistence API) : 자바 진영의 ORM 기술 표준
  • ORM(Object-relational mapping 객체 관계 매핑) : 객체와 RDB가 존재 할 때, ORM 프레임워크가 중간에서 매핑!
  • 사용 이유 : 생산성, 유지보수, 객체 중심 개발 가능, 성능, 표준 등(객체와 RDB를 분리하면서 장점을 가져온다.)

JPA설정하기

  • META-INF/persistence.xml 위치한 JPA 설정파일
  • javax.persistence로 시작: JPA 표준 속성
  • hibernate로 시작: 하이버네이트 전용 속성
 <persistence-unit name="hello">
 <properties>
 <!-- 필수 속성 -->
 <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
 <property name="javax.persistence.jdbc.user" value="sa"/>
 <property name="javax.persistence.jdbc.password" value=""/>
 <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
 <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>

 <!-- 옵션 -->
 <property name="hibernate.show_sql" value="true"/>
 <property name="hibernate.format_sql" value="true"/>
 <property name="hibernate.use_sql_comments" value="true"/>
 <!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
 </properties>
 </persistence-unit> 

JPA는 특정 데이터베이스에 종속 X (하이버네이트는 40가지 이상의 데이터베이스 방언 지원) !!!!

개인적으로 JPA 설정 파일에서 <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
DB에 따라 맞춰서 여러종류의 RDB마다 조금씩 다른 sql 문법을 보정할 수 있다는게 큰 장점 같다. myBatis같은 경우는 sql문을 직접 작성하다보니 거의 없겠지만 RDB종류를 변경하면 미묘한 차이에서 수정해줘야하는 과정이 필요하다.

JPA 구동 방식

  • Persistence 라는 클래스 부터 시작한다.

    Persistence -> META-INF/persistence.xml JPA 설정 정보를 조회 ->
    Persistence -> EntityMangerFactory 클래스 생성(하나만 생성해서 애플리케이션 전체 공유)
    -> EntityManager 다수 생성 (쓰레드 간에 공유x 사용하고 사라짐)

  • JPA 모든 데이터 변경은 트랜잭션 안에서 실행 되어야한다.

JPQL

  • JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어 제공

  • JPA를 사용하면 엔티티 객체를 중심으로 개발한다.

  • 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색한다.
    왜냐하면 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능하고 애플리케이션이 필요한 데이터만 물리적으로 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요하기 때문에 코드가 SQL에 종속적이게 된다

  • 위와 같이 엔티티객체에 대한 쿼리문에 대해 검색할 수 있는 JPQL은 가장 단순한 조회 방법이다.
    ex) 나이가 18살 이상인 회원을 모두 검색하고 싶다면?
    보통의 조회는 EntityManager.find(~~.class , ~~); 이런식인데 검색조건이 붙으면 JPQL을 사용
    EntityManager.createQuery("쿼리문" , ~~.class).getResultList(); 이런식으로 사용

  • SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않으며, JPQL을 한마디로 정의하면 객체 지향 SQL이다

영속성 관리

영속성 컨텍스트

  • JPA내부적 동작원리를 파악 할 수 있음
  • 엔티티를 영구저장하는 환경
  • EntityManager.persist(entity); -> 엔터티를 영속성 컨텍스트 안에다가 저장한다는 뜻
  • 논리적이고 눈에 보이지 않는 개념

영속성 컨텍스트 (entityManager)의 흐름

엔티티 등록
1. persist(~~) 메서드 사용
2. 영속 컨텍스트 내에 1차 캐시에 @Id와 엔티티 저장 그리고 쓰기 지연 SQL 저장소에 SQL문 생성 후 저장
3. commit 과 함께 DB로 SQL문을 넘긴다.
4. 영속성 컨텍스트 사라짐

조회
1.find(~~~) 메서드 사용
2. 영속 컨텍스트 내에 1차 캐시에서 찾는다. 없으면 DB에서 찾은 뒤 1차캐시에 저장한다.
3. 1차캐시에서 엔티티를 반환

엔터티의 생명주기

  • 비영속 (new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 상태
  • 영속 (managed) : 영속성 컨텍스트에 관리되는 상태
  • 준영속 (detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 삭제 (removed) : 삭제된 상태
//1. 객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername(“회원1);

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

//2. 객체를 저장한 상태(영속) - 이 때부터  영속 상태로 관리되기 시작
//  (DB에 저장되는 시기는 아니다. 트랜잭션에서 커밋되어야 DB로 넘어감)
em.persist(member);

//3.회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);

//4.객체를 삭제한 상태(삭제)
em.remove(member);

영속성 컨텍스트(entityManager)의 이점

  • DB와 어플리케이션 사이에 중간다리 역할
  • 조회시 DB가 아닌 영속컨텍스트의 1차 캐시에서 조회한다.
    (큰 이점은 아니다. 고객의 요청(짧은 시간)이 끝나면 영속 컨텍스트를 바로 다 지우기 때문에 캐시도 같이 지워짐)
  • 영속 엔티티의 동일성 보장
    (1차 캐시를 바탕으로 같은 트랜잭션 안에서 조회가 실행되었을 때 동일 객체로 조회 가능)
  • SQL문을 쓰기 지연 하는 SQL 저장소가 영속성 컨텍스트에서 운용된다.
    (transaction.commit(); 이 후 영속성 컨텍스트에 보관 되어있던 SQL문들이 DB로 넘어감)
  • 엔티티 수정 변경 감지
    (commit() 내에 flush()라는 메서드가 있고 이를 통해 1차 캐시에 있는 엔티티(기존 시점)와 스냅샷(저장 되는 시점)을 비교한다.)

플러시

  • 영속성 컨텍스트의 변경내용을 데이터 베이스에 반영한다.
  • 영속성 컨텍스트를 비우지 않는다. (커밋과의 차이)
  • 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화 (변경내용이 주된 목적)
  • 트랜잭션이라는 작업 단위가 중요 -> 커밋 직전에만 동기화 하면 된다.

플러시의 발생과 흐름

  • flush() -> 변경 감지 -> 수정된 엔티티 쓰기 지연 SQL 저장소에 등록 -> flush ->변경 쿼리문 DB에 전송

영속성 컨텍스트를 플러시하는 방법

  • em.flush() : 직접 호출
  • 트랜잭션 커밋 : 플러시 자동 호출
  • JPQL 쿼리 실행 : 플러시 자동 호출

준영속 상태

  • 영속 -> 준영속
  • 영속 상태(1차 캐시에서 관리되는 상태)의 엔티티가 영속성 컨텍스트에서 분리
  • 영속성 컨텍스트가 제공하는 기능을 사용 못한다.

준영속 상태로 만드는 방법

  • em.detach(entity) : 특정 엔티티만 준영속 상태로 전환
  • em.clear() : 영속성 컨텍스트를 완전히 초기화
  • em.close() : 영속성 컨텍스트를 종료
profile
일단 흐자

0개의 댓글