JPA( Java Persistence API )
。JAVA에서ORM 기술표준으로 활용되는API 라이브러리
▶ 호환성을 목적으로DB mapping을 용도로 해당interface의구현체를 생성하여 활용
。ORM에 의해어플리케이션의DB Entity를DB Table과 자동으로Mapping하여DB Entity가 변화 시Update Query를DB에 전달하여매핑된DB Table의 데이터도 변경
。JPA를 구현한 대표적인오픈소스로Hibernate가 존재.
。CRUD를 수행 시 기존JDBC는 개발자가 직접SQL을 작성하는 번거로움이 존재
▶JPA는구현체인Hibernate를 통한API를 사용하는 경우EntityManager가 자동으로SQL을 생성하여CRUD를 수행하므로 간편
。Spring에서는Spring Data JPA로 구현되어있으며EntityManager가 아닌JpaRepository 인터페이스 구현체로DB Entity의CRUD를 수행
@Entity가 선언된Entity Class는 내부의객체를 선언하는 경우Entity 객체로 판단하여연관관계 Mapping을 위한어노테이션(@ManyToOne등 )을 선언해야함.
▶ 일반POJO 객체를 내부에 선언할 필요가 존재 시@Embedded로 선언해야한다.
ORM(Object-Relational Mapping) :
。어플리케이션의DB Entity 객체를RDBMS의DB Table에 자동으로영속화하는 것
▶DB Entity 객체와RDBMS DB Table간 지속적으로 자동으로Mapping하여DB Entity가 변화 시Update Query를DB에 전달하여매핑된DB Table의 데이터도 변경
。SQL을 직접 사용하지 않고,DB Entity 객체를 중심으로DB와 상호작용을 수행
▶RDBMS(H2-DB,mySQL,postgreSQL) 의 변경에도 유연한 적용이 가능.
JPA사용 시 주의사항
지연로딩( Lazy Loading )
。런타임 시점에서 사용 시Query를 실행
▶ 해당Query에 연관된Query가 추가 실행되는N+1 문제의 원인이 될 수 있다.
。주로(fetch = FetchType.LAZY)의연관관계로매핑된Entity객체를추가 조회하여Query를 반복적으로 수행하여N+1 문제가 발생할 수 있다
N+1 문제
。특정Query를 실행 시 여러번Query가 실행되는 문제
ex )댓글조회 시대댓글까지 조회
- 복잡한
Query의 한계
。Query가 복잡한 경우JPA로 실행하기 어렵고@Query또는QueryDSL을 사용
Entity의 설계가 중요
。잘못 설계하면 성능저하.
DB Entity
。ORM에 의해DB의 특정Table를1:1 Mapping한@Entity Class의POJO 객체
。영속성 컨텍스트에 등록되어Entity Manager에 의해DB의 특정Table의데이터로서CRUD가 수행됨
。Entity Class는@Entity선언 후Mapping할DB Table과 동일하게@Id,@ManyToOne등을 선언하여PK,FK를 설정
。DB Entity를클라이언트에게 반환하면 안되며DTO를 정의하여 필요한데이터를 추출하여클라이언트에게 전달
▶DB Entity는연관관계를 통해 다른DB Entity 객체도 포함하고 있으므로
DB Entity의 상태
。비영속/영속/준영속/삭제
비영속( New )
。@Entity가 선언되었으나영속성 컨텍스트에 한번도 등록되지않아 관리되고 있지않은 순수POJO
▶EntityManager.save()에 등록되기전까지는new를 통해 생성된 직후의Entity 객체 상태가비영속으로DB에 반영되지않음
。Class내@OneToMany등의연관관계 매핑이 정의되있더라도영속화되기전까지는 초기화되지않아연관관계가 없는Null상태
영속( Managed )
。DB Entity가영속성 컨텍스트에 등록되어 관리되고 있는 상태
▶JpaRepository객체.save(비영속POJO)를 수행하는 경우Persistence Context에 저장되어 관리
。해당 시점에서@OneToMany등으로 정의된연관관계를 정의하기 위해DB에Query를 전달하여연관관계 Entity객체를 초기화
▶비영속 상태인 경우@OneToMany field는Null인 상태.
。Dirty Checking에 의해DB Entity의 변화를 자동으로 감지하고flush()시점에서 실제DB Table에 반영
。영속화:DB Entity를영속성 컨텍스트에 의해 관리되는 상태로 만드는것을 의미.
준영속( Detached )
。영속성 컨텍스트내 존재하는영속 상태였다가 연결이 끊긴 상태의DB Entity
▶ 더이상영속성 컨텍스트에 의해 관리되지 않음
삭제( Removed )
。Persistence Context에서 완전히 삭제된 상태
▶EntityManager.remove(entity)호출 시 해당 상태로 전환
EntityManager
。영속성 컨텍스트에 등록된DB Entity 객체의 전반적인생명주기를 관리하는 역할을 수행
▶JPA에서 실제SQL을 수행하는객체로서Entity를DB에 저장, 조회, 수정, 삭제하는 역할을 수행
영속성 컨텍스트( Persistence Context )
。JPA가DB Entity 객체를영속 상태로서 영구히 저장 및 관리하는캐싱역할의저장소
▶DB Entity를영구적으로 저장 및 관리하여영속성을 보장
。DB Entity를 등록 시 대기 후flush()가 수행되는 경우매핑된DB Table에 반영됨
。영속성 컨텍스트에서 관리되는DB Entity 객체의 변경 시Dirty Checking에 의해Mapping된DB Table에도 변경 수행
flush():
。commit시 호출되어 기존Pending 상태인 모든Entity를매핑된DB Table에 일괄적으로 반영하도록DB에SQL을 전송하는 역할을 수행
▶Pending:DB Entity변경내용이DB에 반영되지않고영속성 컨텍스트에만 반영된 상태
Dirty Checking
。영속성 컨텍스트내에서 관리되고있는영속 상태의DB Entity가Transaction내에서 변화 시 자동으로 감지하여 변경된 내용을 자동으로 감지하여flush()시점에서UPDATE Query를 생성 및DB로 자동반영하는JPA 기능
▶DB Entity를 변경하는Transaction이COMMIT되는 경우 변경된 정보에 대해서만UPDATE를 자동으로 수행
JPA원리
。Spring Data JPA기준
1.Repository에서JpaRepository를 확장 및JpaRepository에 구현된API(EntityManager.save(DB Entity)) 수행
。Repository:Entity에 접근하기위한인터페이스
。JpaRepository:Entity Manager에 의한CRUD가 이미 구현된인터페이스public interface MemberRepository extends JpaRepository<Member,Long> { }▶
Repository에서JpaRepository<>를 확장해서 해당Entity에 대한CRUD를 수행
2.EntityManager에 의해Persistence Context에DB Entity를 등록
。등록 시 해당Entity의상태(비영속 / 영속 / 준영속 / 삭제)를 추적
3. 추후Transaction에서 등록된DB Entity가 변경된 경우Dirty Checking에 의해변경내용을 감지
。트랜잭션을 통해 변경된 내용은pending 상태로영속성 컨텍스트내에서만 반영
4.트랜잭션을Commit할 경우flush()를 호출하여Pending 상태의변경내용만 갱신하는UPDATE SQL을매핑된DB Table에 전송하여 반영
JPA와 Hibernate의 차이점
。JPA는API/Hibernate는API에 대한구현체로서JPA만으로 사용이 불가능하고 실제Hibernate와 같은JPA 구현체가 존재해야JPA를 통한CRUD를 수행가능
JPA
。API를 정의 ( 객체를 DB의 table로 Mapping하는 방식 정의 )
。@Entity: Interface로서 Entity가 무엇인지 정의
。@Id,@Column: 변수를 DB Table의 Field로 mapping
▶EntityManager에 존재하는 Method를 구현함으로써JPA API사용.
Hibernate
。 대표적인 오픈소스JPA 구현체
。Hibernate JAR을 class path에 추가해서Hibernate를JPA 구현체로 사용.
▶ (ex.@Entity의 경우.jakarta.persistence대신org.hibernate.annotations사용. )
。코드에서 직접Hibernate annotation을 사용하지 않는 이유는 다른 JPA 구현체(Toplink등)이 존재하므로, Hibernate로만 한정해서 사용하지 않기 위해!
。인터페이스처럼 코드는JPA를 사용하여 작성하여추상화하고Hibernate는 코드가 아닌,구현체로만 사용하는것이 좋다.
Dialect:
。JPA또는Hibernate에서 사용하는특정 DB에 해당하는SQL문법과기능을 사용하도록 설정
▶ 각DB는 통일된ANSI SQL를 사용하나 각각 작은 차이가 존재하므로 보완하기위해Dialect를 설정
▶Hibernate는 해당 문법/기능적 차이를Dialect를 통해 자동으로 조정