본문 바로가기
Develop/Spring

JPA(Java Persistence API)와 엔티티 매핑(Entity Mapping)

by jaeyoungb 2022. 11. 1.

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

JPA라는 인터페이스로 정의되어 있는 구현체는 따로 있고, 우리는 그 구현체를 학습하는 것이다.

JPA는 Java Persistence API의 약자이지만, 현재는 Jakarta Persistence라고도 불린다.

 

 

Hibernate ORM

JPA에서 정의해둔 인터페이스를 구현한 구현체로써,

JPA에서 지원하는 기능 이외에 Hibernate 자체적으로 사용할 수 있는 API 역시 지원하고 있다.

 

 

위 그림과 같이, JPA는 데이터 액세스 계층의 상단에 위치한다.

 

JPA의 Persistence영속성, 지속성을 뜻한다. 즉, 무언가를 금방 사라지지 않고 오래 지속되게 한다라는 것이 목적이다.

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

그리고 이렇게 보관된 엔티티 정보는 데이터베이스 테이블에 데이터를 저장, 수정, 조회, 삭제하는데 사용된다.

 

영속성 컨텍스트에는 1차 캐시와 쓰기 지연 SQL 저장소라는 두 개의 영역이 존재한다.

ex) 영속성 컨텍스트에 저장(persist)하는 JPA API를 사용하면, 1차 캐시 영역에 저장된다.

 

 

 

우선, JPA API를 사용하기 위해서는 build.gradle에 JPA 의존 라이브러리를 추가해야 한다.

 

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

 

 

application.yml

 

(1) 엔티티와 매핑되는 테이블을 자동으로 생성해준다.

(2) JPA 동작 과정을 쉽게 볼 수 있도록, JPA API의 SQL 쿼리를 출력해준다.

 

 

 

영속성 컨테이너에 엔티티 저장

엔티티 클래스에 @Entity, @Id 애너테이션을 추가하면, JPA에서 해당 클래스를 엔티티로 인식한다.

@GeneratedValue기본키가 되는 식별자를 자동으로 설정해준다.

 

 

JpaBasicConfig 클래스 설정

JpaBasicConfig 클래스

 

(1)

EntityManager라는 클래스가 JPA의 영속성 컨텍스트를 관리한다.

위에서 선언한 em이라는 객체는 EntityManagerFactory 객체를 Spring으로부터 DI 받을 수 있다.

EntityManagerFactory의 createEntityManager() 메서드를 이용해서 EntityManager 클래스의 객체를 얻을 수 있다.

그 후에는 EntityManager 클래스의 객체를 통해서 JPA의 API 메서드를 사용할 수 있다.

 

(2)

EntityManager를 통해 Transaction 객체를 얻는다. 이 객체를 기준으로 데이터베이스의 테이블에 데이터를 저장한다.

 

 

 

이제 example 메서드의 구현 내용들을 보자.

 

example 메서드

 

이 메서드 구현 내용들을 요약하자면,

 

1. member1, member2 객체가 생성되고 persist() 메서드를 통해 영속성 컨텍스트의 1차 캐시에 저장된다.

2. 쓰기 지연 SQL 저장소INSERT 쿼리가 등록된다.

3. commit() 메서드에 의해, SQL 저장소에 있던 INSERT 쿼리가 실행되고, 저장소에서는 제거된다.

4. find() 메서드에 의해, 1차 캐시에 해당 객체가 있는지 조회하고, 없으면 테이블에 SELECT 쿼리를 전송해서 조회한다.

5. member2에서 조회된 객체를 setter 메서드를 통해 변경한다.

6. commit() 메서드에 의해, 쓰기 지연 SQL 저장소에 등록된 UPDATE 쿼리가 실행된다.

 

 

영속성 컨텍스트 내에서 persist() 후 commit()을 진행하면, 쓰기 지연 SQL 저장소의 쿼리가 실행되고 삭제된다.

(https://www.nowwatersblog.com/jpa/ch3/3-4)

 

여기서 중요한 점들은,

 

1. 데이터베이스의 테이블에 데이터를 저장하기 위해서는 Transaction이 필요하고, 그 Transaction을 시작하기 위해서는 begin() 메서드를 먼저 호출해야 한다.

2. commit() 메서드가 호출되면, 영속성 컨텍스트에 저장되어 있는 객체를 데이터베이스의 테이블에 저장한다.

3. EntityManager의 find() 메서드로 객체를 찾지 못하면, '테이블에 직접' SELECT 쿼리를 전송한다.

4. commit(), find() 메서드가 호출되고 나면, 쓰기 지연 SQL 저장소에 있는 INSERT, SELECT 쿼리들은 사라진다.

5. setter 메서드로 값을 변경한 후, commit() 메서드를 호출하면, 이전에 떠 놓은 스냅샷과 비교한 후, 쓰기 지연 SQL 저장소에 UPDATE 쿼리를 등록, 실행한다.

6. EntityManager의 commit() 메서드가 호출되면, JPA 내부적으로 EntityManager의 flush() 메서드가 호출되어 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영한다.

 

 

++

 

 

 

엔티티 매핑

 

엔티티 매핑 작업은 다음과 같다.

 

1. 객체와 테이블 간의 매핑

2. 기본키 매핑

3. 필드(멤버 변수)와 컬럼 간의 매핑

4. 엔티티 간의 연관 관계 매핑

 

 

 

엔티티와 테이블 간의 매핑

 

@Entity

  • 클래스 레벨에 추가하고, JPA 관리 대상 엔티티가 된다.
  • 애트리뷰트
    • name : 엔티티 이름을 설정 / 기본값으로 클래스 이름

@Table

  • 애트리뷰트
    • name : 테이블 이름을 설정 / 기본값으로 클래스 이름

 

주의)

@Table은 옵션이지만, @Entity와 @Id 애너테이션은 필수이다.

중복되는 엔티티 클래스가 없고, 테이블 이름이 클래스 이름과 같을 경우, @Entity, @Table 애너테이션에 name 애트리뷰트를 따로 지정하지 않고, 클래스 이름(기본값)으로 사용하는 게 권장된다.

파라미터가 없는 기본 생성자는 필수로 추가한다.

 

 

 

기본키 매핑 (필수)

 

JPA에서 지원하는 기본키 생성 전략은 다음과 같다.

 

기본키 직접 할당 : @Id 추가

IDENTITY : @GeneratedValue(strategy = GenerationType.IDENTITY) 추가

SEQUENCE : @GeneratedValue(strategy = GenerationType.SEQEUNCE) 추가

(SEQUENCE 전략은 IDENTITY와 다르게 영속성 컨텍스트에 저장되기 전에 데이터베이스가 시퀀스에서 기본키에 해당하는 값을 제공한다)

 

 

이외에도 AUTO 전략이 있다.

@GeneratedValue(strategy = GenerationType.AUTO)를 지정하면 JPA가 데이터베이스의 Dialect에 따라 적절한 전략을 자동으로 선택한다.

JPA가 지원하는 표준 문법이 아닌 특정 데이터베이스에 특화된 기능을 사용할 경우 이 Dialect가 처리해준다.

 

 

 

필드(멤버 변수)와 컬럼 간의 매핑

 

@Column : 필드와 컬럼을 매핑해주는 애너테이션

 

애트리뷰트

  • nullable : 컬럼에 null 값 허용 여부, 디폴트 값은 true
  • updatable : 컬럼 데이터를 수정할지 여부, 디폴트 값은 true
  • unique : 하나의 컬럼을 고유한 값으로 설정할지 여부, 디폴트 값은 false
  • length : 컬럼에 저장할 수 있는 문자 길이, 디폴트 값은 255

@Transient : 테이블 컬럼과 매핑하지 않고 임시 데이터를 메모리에서 사용하기 위한 용도

@Enumerated : enum 타입과 매핑할 때 사용

  • EnumType.ORDINAL : enum의 순서를 나타내는 숫자를 테이블에 저장
  • EnumType.String : enum의 이름을 테이블에 저장 (권장)