TIL-JPA

정민교·2022년 11월 9일
0

codestates-TIL

목록 보기
1/1

JPA(Java Persistence API)

Java 진영에서 사용하는 ORM(Object-Relational Mapping) 기술의 표준 사양(명세, 스펙)

표준 사양은 Java의 인터페이스로 정의되어 있음. Jakarta Persistence라고도 불림.

JPA 표준 사양 구현체

Hibernate ORM, EclipseLink, DataNucleus 등

Hibernate를 많이 사용

JPA 표준 사양 구현체로 JPA에서 지원하는 기능 이외에 Hibernate 자체적으로 사용할 수 있는 API 역시 지원한다.

ORM(Object Relational Mapping)

객체와 DB 테이블을 매핑해서 엔티티 클래스의 객체에 대한 정보를 테이블에 저장하는 기술

데이터 액세스 계층에서의 JPA 위치

JPA는 데이터 액세스 계층 상단에 위치

DB 접근 작업은 JPA를 거쳐 구현체인 Hibernate ORM을 통하고 Hibernate ORM은 내부적으로 JDBC API를 이용해서 데이터베이스에 접근한다.

JPA → Hibernate → JDBC API

영속성 컨테스트(Persistence Context)

뭐가 오래 지속 되는가…

테이블과 매핑되는 엔티티 클래스의 객체에 대한 정보를 영속성 컨텍스트(Persistence Context)라는 곳에 보관해서 애플리케이션 내에서 오래 지속되도록 한다.

보관된 엔티티 객체 정보는 DB 테이블에 저장, 수정, 조회, 삭제하는데 사용된다.

1차 캐시

JPA API 중에서 엔티티 객체를 영속성 컨텍스트에 저장하는 API를 사용하면 영속성 컨텍스트의 1차 캐시에 저장된다.

쓰기 지연 SQL 저장소

영속성 컨텍스트의 1차 캐시에 저장된 엔티티 객체들을 DB에 저장하기 위한 SQL 쿼리문이 저장된다.

커밋 후에 쓰기 지연 SQL 저장소에 있던 쿼리가 실행되어 비워진다. 1차 캐시에 있던 엔티티 객체들은 계속 남아있다.

JPA API로 영속성 컨텍스트 이해하기

JPA 설정(application.yml)

spring:
  h2:
    console:
      enabled: true
      path: /h2
  datasource:
    url: jdbc:h2:mem:test
  jpa:
    hibernate:
      ddl-auto: create # 스키마 자동 생성: create, update, create-drop, validate, none
    show-sql: true # SQL 쿼리 출력
    properties:
      hibernate:
        format_sql: true
  • ddl-auto: create 엔티티 클래스를 정의하고 애플리케이션 실행 시, 엔티티와 매핑되는 테이블을 데이터베이스에 자동으로 생성 해준다(data-JDBC 에서는 schema.sql 파일에 DB 테이블 스키마를 작성하고 schema-locations: {"경로"} 지정했다.
  • show-sql: true 쿼리 로그 출력

JPA API 사용

  • @Entity @Id : 클래스에 추가해주면 JPA에서 이 클래스를 엔티티 클래스로 인식한다.
  • @GeneratedValue : 식별자를 생성해주는 전략을 지정할 때 사용(맨 밑에 추가 설명)
  • EntityManagerFactory : Spring이 DI 해준다. EntityManagerFactory 객체의 createEntityManager() 메소드로 EntityManager 객체를 얻을 수 있다.
  • EntityManager : JPA 영속성 컨텍스트를 관리한다. EntityManager 클래스의 객체를 통해 JPA API 메소드를 사용할 수 있다.
    • persist(엔티티 객체) : 영속성 컨텍스트의 1차 캐시에 엔티티 객체 저장.
      • 1차 캐시에 앤티티 객체가 저장되고 엔티티 객체를 저장하기 위한 쿼리문(INSERT)이 쓰기 지연 SQL 저장소에 저장된다.
    • update()?
      • 영속성 컨텍스트에 엔티티 객체를 저장할 때 그 객체의 상태 그대로 가지고 있는 스냅샷을 생성한다.
      • 트랜잭션 커밋할 때 현재 1차 캐시에 있는 엔티티 객체의 현재 상태와 이전에 찍어놓은 스냅샷을 비교해서 변경된 값이 있다면 쓰기 지연 저장소에 UPDATE 쿼리를 등록하고 쿼리를 실행한다.
      • update() 같은 API 가 있는 것은 아니고 1차 캐시에 저장된 객체를 가져와서 객체 정보 수정 후에 트랜잭션 커밋을 하면 DB 테이블 업데이트가 이루어진다.
    • find(앤티티 객체 클래스 타입, 앤티티 객체의 식별자 값) : 영속성 컨텍스트의 1차 캐시에서 해당 엔티티 객체 찾음.
      • 1차 캐시에 해당 엔티티 객체가 없다면 DB에서 SELECT 쿼리를 전송해서 가져온다. 여기서 없으면 null 반환
    • remove(엔티티 객체) : 영속성 컨텍스트의 1차 캐시에 있는 엔티티 제거 요청
      • 트랜잭션 커밋 하면 1차 캐시에 해당 엔티티를 제거하고, 쓰기 지연 SQL 저장소에 등록된 DELETE 쿼리를 날린다.
    • flush() : 영속성 컨텍스트의 변경사항을 테이블에 반영한다.
      • 트랜잭션 commit() 을 호출하면 내부적으로 Entitymanger 의 메소드인 flush() 가 호출된다.
  • Transaction : EntityManger 객체로부터 getTransaction() 메소드를 이용해 얻을 수 있다.
    • 트랜잭션을 시작하려면 begin() 을 먼저 호출한다.
    • 엔티티 객체를 영속성 컨텍스트에 저장하고
    • commit() 을 호출해 영속성 컨텍스트 1차 캐시에 저장된 엔티티 객체들을 DB 테이블에 처리(저장, 수정, 삭제)하기 위해 쓰기 지연 SQL 저장소에 있는 SQL 쿼리문을 실행하여 앤티티 객체들을 DB 테이블에 처리한다.
    • commit() 호출 후에 쓰기 지연 SQL 저장소에 등록된 쿼리문(INSERT, UPDATE, DELETE 등)이 모두 실행되고 실행된 쿼리는 제거된다. 1차 캐시에 엔티티 객체들은 아직 남아있다.
    • commit() 호출 후에 트랜잭션을 시작하려면 다시 begin() 을 호출해야 한다.

@GeneratedValue(strategy = ...)

  • 지금까지 설명한 쓰기 지연은 strategy가 GenerationType.AUTO 인 경우다.
  • GenerationType.IDENTITY 의 경우는 persist를 하면 바로 DB에 쿼리를 날린다.
    • Hibernate: call next value for hibernate_sequence 테이블에서 식별자용 시퀀스를 가져와서 1차 캐시에 채운다.
      • 식별자를 테이블에서 가져와야 해서 식별자 없이 엔티티 객체를 영속성 컨텍스트에 저장하고 INSERT 쿼리를 날린다.
      • 그 후에 식별자를 1차 캐시에 업데이트 한다.
      • 따라서 쓰기 지연 SQL이 이루어지지 않는다.
profile
백엔드 개발자

0개의 댓글