23.04.21 JPA

김민성·2023년 4월 21일
1

JPA

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

그림 3-49 처럼 JPA는 데이터 액세스 계층의 상단에 위치한다.
데이터 저장,조회 등의 작업은 JPA를 거쳐 JPA의 구현체인 Hibernate ORM을 통해서 이루어지며
Hibernate ORM은 내부적으로 JDBC API를 이용해서 데이터베이스에 접근하게 된다.

영속성 컨텍스트(Persistence Context)

ORM은 객체와 데이터베이스 테이블의 매핑을 통해 엔티티 클래스 객체 안에 포함된 정보를 테이블에 저장하는 기술이다.
JPA에서는 테이블과 매핑되는 엔티티 객체 정보를 영속성 컨텍스트(Persistence Context)라는 곳에 보관해서 애플리케이션 내에서 오래 지속 되도록 하고 이렇게 보관된 엔티티 정보는 데이터베이스 테이블에 데이터를 저장,수정,조회,삭제하는 데 사용된다.

JPA를 사용하기 전 사전 준비

build.gradle 설정

dependencies{
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 
    ...
}

JPA 설정(application.yml)

spring:
  h2:
    console:
      enabled: true
      path: /h2     
  datasource:
    url: jdbc:h2:mem:test
  jpa:
    hibernate:
      ddl-auto: create  # (1) 스키마 자동 생성
    show-sql: true      # (2) SQL 쿼리 출력

(1)과 같이 설정을 추가해 주면 우리가 JPA에서 사용하는 엔티티 클래스를 정의하고 애플리케이션 실행 시, 이 엔티티와 매핑되는 테이블을 데이터베이스에 자동으로 생성해준다.

JPA 동작 확인을 위한 Member 엔티티 클래스

import lombok.Getter;

import javax.persistence.*;

@Getter
@Setter
@NoArgsConstructor
@Entity  // (1)
public class Member {
    @Id  // (2)
    @GeneratedValue  // (3)
    private Long memberId;

    private String email;

    public Member(String email) {
        this.email = email;
    }
}

(1) @Entity 와 (2) @Id 애너테이션을 추가해주면 JPA에서 해당 클래스를 엔티티 클래스로 인식한다.

(3) @GeneratedValue 애너테이션은 데이터베이스 테이블에서 기본키가 되는 식별자를 자동으로 설정해준다.

private void example02() {
        
        tx.begin(); // Transaction을 시작하기 위해서 tx.begin() 메서드를 먼저 호출
        Member member = new Member("hgd@gmail.com");

        
        em.persist(member); // 영속성 컨택스트에 저장

        
        tx.commit(); // 영속성 컨텍스트에 저장되어 있는 member 객체를 데이터베이스 테이블에 저장

        
        Member resultMember1 = em.find(Member.class, 1L);

        System.out.println("Id: " + resultMember1.getMemberId() + ", email: " + resultMember1.getEmail());

        
        Member resultMember2 = em.find(Member.class, 2L);

        
        System.out.println(resultMember2 == null);

    }
  • em.persist() 를 호출하면 영속성 컨텍스트의 1차 캐시에 엔티티 클래스의 객체가 저장되고, 쓰기 지연 SQL 저장소에 INSERT 쿼리가 등록된다.
  • tx.commit() 을 하는 순간 쓰기 지연 SQL 저장소에 등록된 INSERT 쿼리가 실행되고, 실행된 INSERT 쿼리는 쓰기 지연 SQL 저장소에서 제거된다.
  • em.find()를 호출하면 먼저 1차 캐시에서 해당 객체가 있는지 조회하고, 없으면 테이블에 SELECT 쿼리를 전송해서 조회한다.

tx.commit()을 했기 때문에 member에 대한 INSERT 쿼리는 실행되어 쓰기 지연 SQL 저장소에서 사라진다.

영속성 컨텍스트와 테이블에 엔티티 업데이트

private void example04() {
       tx.begin();
       em.persist(new Member("hgd1@gmail.com"));    
       tx.commit();    


       tx.begin();
       Member member1 = em.find(Member.class, 1L);  // (1)
       member1.setEmail("hgd1@yahoo.co.kr");       // (2)
       tx.commit();   
    }

(1) - 테이블에 저장된 member 객체를 영속성 컨텍스트의 1차 캐시에서 조회한다.
(2) - setter 메서드로 값을 변경하기만 하면 업데이트 로직이 완성된다.
🍋 조회 시 테이블에서 조회하는 것이 아닌 영속성 컨텍스트의 1차 캐시에 이미 저장된 객체가 있기 때문에 영속성 컨텍스트에서 조회한다.

영속성 컨텍스트와 테이블의 엔티티 삭제

private void example05() {
        tx.begin();
        em.persist(new Member("hgd1@gmail.com"));  
        tx.commit();    

        tx.begin();
        Member member = em.find(Member.class, 1L);   
        em.remove(member);     // (1)
        tx.commit(); // (2)  
    }

(1) - em.remove(member)를 통해 영속성 컨텍스트의 1차 캐시에 있는 엔티티를 제거를 요청한다.
(2) - 영속성 컨텍스트의 1차 캐시에 있는 엔티티를 제거하고, 쓰기 지연 SQL 저장소에 등록된 DELETE 쿼리가 실행 된다.

0개의 댓글