TIL(Today I Learned)

JPA(Java Persistence API)의 이해 1

Happy._. 2024. 5. 9. 23:14

JPA(Java Persistence API)

  • ORM의 한 종류, Java 및 Kotlin의 객체를 사용해 DB를 쉽게 조회, 조작할 수 있도록 해 줌

ORM(Object-Relational Mapping)

  • 객체와 관계형 DB 간의 매핑을 담당
  • 별도의 SQL 쿼리를 작성하지 않아도 객체를 DB에 저장 및 조회 가능
  • 객체를 활용하므로 객체 지향 프로그램 가능 및 재사용성 증대
  • DB에 종속적이지 않음(DB 변경 시 코드 최소화)
  • 필요에 따라 데이터를 캐싱하므로 효율적인 데이터 조회 가능 
  • ORM 개념 학습 러닝 커브 有
  • 복잡한 쿼리나 특수한 DB 기능을 사용하는 경우 직접 SQL 작성이 효율적

JDBC, Hibernate, JPA, Spring Data JPA

  • JDBC(Java Database Connectivity)
    • Java 애플리케이션에서 DB에 접근, 각종 SQL을 사용할 수 있게 해 줌
    • JDBC API, JDBC Driver로 구성
    • JDBC API는 Interface, JDBC Driver는 Interface의 DB별 구현체
    • 사용자는 Driver 설정만으로 동일 Interface를 통해 다른 DB 사용 가능
  • JPA(Java Persistence API)
    • JDBC API를 내부적으로 사용
    • SQL을 직접 사용하기보다 객체지향적으로 DB를 다룰 수 있도록 하는 역할을 하는 ORM
  • Hibernate
    • JPA Interface의 구현체 중 하나로 대표적으로 많이 사용
    • 내부적으로 JDBC API 사용
  • Spring Data JPA
    • JPA를 쓰기 편하게 만들어 놓은 라이브러리
    • JPA를 한 단계 더 추상화시킨 Repository라는 인터페이스를 제공
    • Repository의 구현체는 내부적으로 JPA를 사용

JPA의 Entity

  • 테이블과 맵핑되는 객체
  • 다음 코드처럼 클래스 상단에 @Entity 어노테이션을 붙이면 JPA에서 관리하는 객체로 작동함
@Entity
@Table(name = "post")
class Post(
    @Column(name = "title")
    var title: String,

    // ... 

    @OneToMany(mappedBy = "post")
    val comments: List<Comment> = mutableListOf(),

    @ManyToOne
    @JoinColumn(name = "author_id", nullable = false)
    val author: User,
) {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long? = null
}
  • @Entity : Java 객체로 맵핑
  • @Table : 관계있는 테이블을 명시하며 생략 가능(생략 시 JPA는 Entity 클래스명을 이름으로 사용, 테이블 자동 맵핑)
  • @Id : Entity의 PK(Primary Key)를 지정
  • @GeneratedValue : 자동으로 생성되는 식별자 사용
  • @Column : DB 컬럼과 맵핑
  • @ManyToOne, @OneToMany, @OneToOne, @ManyToMany : 객체 간 관계 설정

JPA의 Persistence Context

  • Persistence Context에 Entity 포함 유무에 따라 DB에 변경사항을 저장하여 영속성 부여 여부를 결정
  • 예) 한 트랜잭션 안에서 데이터를 DB로부터 가져올 때 이 데이터는 Persistence Context에 포함된 상태이며 변경된 값은 트랜잭션이 끝날 때 DB에 반영

JPA는 Persistence Context 개념 활용, 아래 역할들을 수행

  • Entity의 상태 추적
    • Persistence Context는 Entity가 Transient(New), Managed, Detached, Removed 등의 상태에 있는지 추적
    • JPA는 다음 Entity의 상태를 통해 트랜잭션 종료 시 DB에 최종적으로 어떤 쿼리를 보낼지 결정
    • 트랜잭션이 끝나는 시점에 Managed, Removed 상태의 Entity들의 변경사항이 DB에 반영됨 
      • Transient : 아직 Persistence Context에 포함되지 않은 새로운 Entity 상태
      • Managed : Persistence Context에 저장된 상태
      • Detached : Persistence Context에 저장되었다가 분리된 상태
      • Removed : 삭제된 상태
  • 캐싱(Caching)
    • Persistence Context 내 Entity를 Map 형태로 임시 저장
    • 동일한 Entity 조회 시 DB를 직접 조회하지 않고 해당 Entity를 사용할 수 있게 해 줌
  • 지연 로딩(Lazy Loading) 및 즉시 로딩(Eager Loading)
    • 연관관계에 있는 Entity를 지연로딩하거나 즉시 로딩할 수 있는 기능을 제공
    • 지연 로딩 : 연관된 Entity가 실제 필요한 시점에 DB에서 로드할 수 있도록 함
    • 즉시 로딩 : 연관된 Entity에 접근하는 순간 쿼리가 수행됨
  • 트랜잭션(Transaction)을 통한 쓰기 지연
    • 코드 상에서 변경한 Entity를 바로 반영하지 않음
    • Entity의 상태 변경을 통해 SQL 저장소에 쿼리를 저장
    • 최종적으로 트랜잭션이 종료되는 시점(commit) 이전에 DB에 모아둔 쿼리를 보내 DB와 영속성 컨텍스트를 동기화
    • commit 종료 이전 쿼리를 보내 동기화하는 것을 flush라고 함
    • flush로 전송된 쿼리는 rollback이 가능, commit 완료 후에는 트랜잭션이 끝나므로 rollback 불가
  • Dirty Checking
    • Entity의 변경 사항을 추적하는 과정
    • Dirty Checking은 Entity가 영속성 컨텍스트에 저장된 상태(Managed)에 대해서만 수행됨