JPA / ORM 개요

이정수·2025년 10월 19일

Spring JPA

목록 보기
1/9

JPA ( Java Persistence API )
JAVA에서 ORM 기술표준으로 활용되는 API 라이브러리
▶ 호환성을 목적으로 DB mapping을 용도로 해당 interface구현체를 생성하여 활용

ORM에 의해 어플리케이션DB EntityDB Table과 자동으로 Mapping하여 DB Entity가 변화 시 Update QueryDB에 전달하여 매핑DB Table의 데이터도 변경

JPA를 구현한 대표적인 오픈소스Hibernate가 존재.

CRUD를 수행 시 기존 JDBC는 개발자가 직접 SQL을 작성하는 번거로움이 존재
JPA구현체Hibernate를 통한 API를 사용하는 경우 EntityManager가 자동으로 SQL을 생성하여 CRUD를 수행하므로 간편

Spring에서는 Spring Data JPA로 구현되어있으며 EntityManager가 아닌 JpaRepository 인터페이스 구현체DB EntityCRUD를 수행

@Entity가 선언된 Entity Class는 내부의 객체를 선언하는 경우 Entity 객체로 판단하여 연관관계 Mapping을 위한 어노테이션 ( @ManyToOne 등 )을 선언해야함.
▶ 일반 POJO 객체를 내부에 선언할 필요가 존재 시 @Embedded로 선언해야한다.

  • ORM (Object-Relational Mapping) :
    어플리케이션DB Entity 객체RDBMSDB Table에 자동으로 영속화 하는 것
    DB Entity 객체RDBMS DB Table 간 지속적으로 자동으로 Mapping하여 DB Entity가 변화 시 Update QueryDB에 전달하여 매핑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의 특정 Table1:1 Mapping@Entity ClassPOJO 객체

영속성 컨텍스트에 등록되어 Entity Manager에 의해 DB의 특정 Table데이터로서 CRUD가 수행됨

Entity Class@Entity 선언 후 MappingDB 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 등으로 정의된 연관관계를 정의하기 위해 DBQuery를 전달하여 연관관계 Entity객체를 초기화
    비영속 상태인 경우 @OneToMany fieldNull인 상태.

    Dirty Checking에 의해 DB Entity의 변화를 자동으로 감지하고 flush() 시점에서 실제 DB Table에 반영

    영속화 : DB Entity영속성 컨텍스트에 의해 관리되는 상태로 만드는것을 의미.

  • 준영속( Detached )
    영속성 컨텍스트 내 존재하는 영속 상태였다가 연결이 끊긴 상태의 DB Entity
    ▶ 더이상 영속성 컨텍스트에 의해 관리되지 않음

  • 삭제 ( Removed )
    Persistence Context에서 완전히 삭제된 상태
    EntityManager.remove(entity) 호출 시 해당 상태로 전환

  • EntityManager
    영속성 컨텍스트에 등록된 DB Entity 객체의 전반적인 생명주기를 관리하는 역할을 수행
    JPA에서 실제 SQL을 수행하는 객체로서 EntityDB에 저장, 조회, 수정, 삭제하는 역할을 수행

  • 영속성 컨텍스트 ( Persistence Context )
    JPADB Entity 객체영속 상태로서 영구히 저장 및 관리하는 캐싱 역할의 저장소
    DB Entity영구적으로 저장 및 관리하여 영속성을 보장

    DB Entity를 등록 시 대기 후 flush()가 수행되는 경우 매핑DB Table에 반영됨

    영속성 컨텍스트에서 관리되는 DB Entity 객체의 변경 시 Dirty Checking에 의해 MappingDB Table에도 변경 수행

    flush() :
    commit 시 호출되어 기존 Pending 상태인 모든 Entity매핑DB Table에 일괄적으로 반영하도록 DBSQL을 전송하는 역할을 수행
    Pending : DB Entity 변경내용이 DB에 반영되지않고 영속성 컨텍스트에만 반영된 상태



  • Dirty Checking
    영속성 컨텍스트 내에서 관리되고있는 영속 상태DB EntityTransaction 내에서 변화 시 자동으로 감지하여 변경된 내용을 자동으로 감지하여 flush() 시점에서 UPDATE Query를 생성 및 DB로 자동반영하는 JPA 기능
    DB Entity를 변경하는 TransactionCOMMIT되는 경우 변경된 정보에 대해서만 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 ContextDB Entity를 등록
。등록 시 해당 Entity상태 ( 비영속 / 영속 / 준영속 / 삭제 )를 추적


3. 추후 Transaction에서 등록된 DB Entity가 변경된 경우 Dirty Checking에 의해 변경내용을 감지
트랜잭션을 통해 변경된 내용은 pending 상태영속성 컨텍스트 내에서만 반영


4. 트랜잭션Commit할 경우 flush()를 호출하여 Pending 상태변경내용만 갱신하는 UPDATE SQL매핑DB Table에 전송하여 반영

JPA와 Hibernate의 차이점
JPAAPI / HibernateAPI에 대한 구현체로서 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에 추가해서 HibernateJPA 구현체로 사용.
    ▶ (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를 통해 자동으로 조정
profile
공부기록 블로그

0개의 댓글