JPA (3)

 

 

SpringBoot에서 JPA를 사용할 때

application.yml 또는 application.properties 파일에서 설정을 해주어야 한다.

ddl-auto는 JPA 설정중에 빌드시 JPA가 어떻게 자동으로 테이블을 생성해줄지에 대한 설정을 지정한다.

 

 

 

➤ ddl-auto 옵션 종류

 

  • create: 기존테이블 삭제 후 다시 생성 (DROP + CREATE)
  • create-drop: 테이블 생성 후 종료시점에 테이블 DROP
  • update: 변경분만 반영(운영DB에서는 사용하면 안됨)
  • validate: 엔티티와 테이블이 정상 매핑되었는지만 확인
  • none: 사용하지 않음(사실상 없는 값이지만 관례상 none이라고 한다.)

 

 

⚠️ 주의사항

 

  • 운영 장비에서는 절대 crate, create-drop, update를 사용하면 안된다.
  • create는 로컬환경에서만 사용한다
  • 개발 초기 단계에는 create 또는 update 를 사용한다.
  • 테스트 서버는 update 또는 validate 를 사용한다.
  • 스테이징과 운영 서버는 validate 또는 none 을 사용한다.

 

 

 

출처 : https://smpark1020.tistory.com/140

 

 

'SpringBoot > Spring 기초' 카테고리의 다른 글

[Spring] Spring Rest Docs 사용을 위한 설정  (0) 2022.08.16

 

 

 

 

JPA 엔티티(Entity) 매핑

 

 

➤ 엔티티 매핑

 

JPA의 매핑 애너테이션을 이용하면 데이터베이스의 테이블과 엔티티 클래스를 매핑할 수 있다.

 

 

▶️ @Entity

  • 엔티티 클래스와 테이블을 자동으로 매핑해준다.
  • 이 애너테이션을 붙이면 JPA 관리 대상 엔티티가 된다.
  • name attribute를 설정하지 않으면 기본적으로 클래스명과 같은 테이블 명을 매핑한다.
  • 테이블 명과 엔티티 클래스 명이 다를 경우 name attribute를 설정해주어야 한다.

 

 

▶️ @Table

  • 데이터베이스의 테이블 이름을 설정할 때 사용한다.
  • name 애트리뷰트를 설정하지 않으면 기본값으로 클래스 이름을 테이블 이름으로 사용한다.
  • @Table 은 옵션이고 추가하지 않을 경우 클래스 이름을 테이블 이름으로 사용한다.

 

 

 

⚠️ 주의 사항

  • @Table ➡️ 옵션
  • @Entity, @Id ➡️ 필수
  • 파라미터가 없는 기본 생성자는 필수로 추가해주자

 

 

➤ 기본키 매핑

 

데이터베이스 테이블에 기본키 설정은 필수이다.

JPA에서 기본키 매핑은 @Id 를 필드에 추가해주면 되는데 JPA에서 어떤 방식으로 기본키를 생성할 것인지에 대한 다양한 전략을 지원해준다.

 

✅ 기본키 직접 할당

애플리케이션 코드 상에서 기본키를 직접 할당해주는 방식이다.

 

 

✅ 기본키 자동 생성

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long memberId;

 

  • IDENTITY
    • 기본키 생성을 데이터베이스에 위임한다.
    • 데이터베이스에서 기본키를 생성해주는 대표적인 방식은 MySQL의 AUTO_INCREMENT 기능으로 자동 증가 숫자를 기본키로 사용하는 방식이 있다.
  • SEQUENCE
    • 데이터베이스에서 제공하는 시퀀스를 사용해서 기본키를 생성하는 전략이다.
  • TABLE
    • 별도의 키 생성 테이블을 사용하는 전략이다.
  • AUTO
    • JPA가 데이터 베이스 Dialect에 따라서 적절한 전략을 자동으로 선택한다.

 

 

TABLE 전략은 키 생성 전용 테이블을 별도로 만들어야 되고, 키를 조회하고 업데이트할 때 쿼리를 전송해야하기 때문에 성능면에서 떨어진다.

 

https://docs.jboss.org/hibernate/orm/5.6/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators-table

 

Hibernate ORM 5.6.10.Final User Guide

Fetching, essentially, is the process of grabbing data from the database and making it available to the application. Tuning how an application does fetching is one of the biggest factors in determining how an application will perform. Fetching too much dat

docs.jboss.org

 

 

 

▶️ 참고) Dialect란?

 

Dialect는 JDBC 타입과 SQL 타입 간에 연결하는 역할을 한다.

Dialect를 사용하면 Hibernate 가 특정 관계형 데이터베이스에 최적화된 SQL을 생성할 수 있다.

Hibernate Dialect 클래스를 기반으로 특정 데이터베이스에 대한 쿼리를 만든다.

hibernate dialect 는 프레임워크에 어떻게 hibernate 쿼리를 SQL 쿼리로 바꿀 지에 대한 정보를 제공해준다.

 

  • 적절한 SQL 쿼리를 생성한다.
  • 애플리케이션이 두 개 이상의 데이터베이스와 연결되어 있을 경우 특정 데이터베이스와 상호작용할 수 있다.
  • 구성 파일에 지정되지 않은 경우에도 데이터베이스 소프트웨어를 기반으로 hibernate 구성 파일 속성에 대한 기본값을 설정한다.

 

https://www.geeksforgeeks.org/hibernate-sql-dialects/

 

Hibernate - SQL Dialects - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

 

 

 

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

 

 

▶️ @Column

 

  • 필드와 데이터베이스의 칼럼을 매핑해주는 애너테이션이다.
  • 이 애너테이션이 없고 필드만 정의되어 있다면 JPA는 기본적으로 이 필드가 테이블의 칼럼과 매핑되는 필드라고 간주하고 @Column 애너테이션에 사용되는 attribute 값은 모두 디폴트로 적용된다.

Attribute

  • nullable
    • default : true
    • 칼럼에 null을 허용할지 여부를 설정
  • updatable
    • 등록한 이후 칼럼 데이터를 수정할 수 있는지 여부를 지정한다.
    • default : true
  • unique
    • 하나의 칼럼에 unique 제약 조건을 설정한다. (중복 허용 x)
    • default : false
  • length
    • 칼럼에 저장할 수 있는 문자 길이를 지정한다.
    • default : 255
  • name
    • default : 필드 명
    • 필드와 매핑되는 칼럼의 이름이 필드명과 다를 경우 지정해 줄 수 있다.

 

 

▶️ @Temporal

 

  • java.util.Date, java.util.Calendar 타입을 매핑하기 위해서 이 애너테이션을 추가해야 한다.
  • LocalDate, LocalDateTime 타입일 경우는 생략가능하다.

 

 

 

▶️ @Transient

 

  • 이 애너테이션을 필드에 추가하면 테이블 칼럼과 매핑하지 않는다.
  • 데이터베이스에 저장하지 않고 조회할 때도 매핑되지 않는다.
  • 주로 임시 데이터를 메모리에서 사용하기위한 용도로 사용된다.

 

 

▶️ @Enumerated

 

  • enum 타입과 칼럼을 매핑할 때 사용한다.
  • Attribute
    • EnumType.ORDINAL : enum의 순서를 나타내는 숫자를 테이블에 저장한다.
    • EnumType.STRING : enum 이름을 테이블에 저장한다.

 

⚠️ 주의

EnumType.ORDINAL 로 지정할 경우

기존에 정의되어 있는 enum 사이에 새로운 enum을 추가한다면 그때부터 테이블에 이미 저장되어 있는 enum 순서 번호와 enum 에 정의되어 있는 순서가 일치하지 않게 되는 문제가 발생한다.

 

 

 

@Column doc

https://docs.oracle.com/javaee/7/api/

 

Java(TM) EE 7 Specification APIs

 

docs.oracle.com

 

 

 

 

 

엔티티 간의 연관관계 매핑

 

 

➤ 연관관계 매핑이란?

 

엔티티 클래스 간의 관계를 만들어 주는 것이다.

 

엔티티 간의 참조할 수 있는 객체수에 따라서

일대다(1:N), 다대일(N:1), 다대다(N:N), 일대일(1:1) 관계로 나눌 수 있다.

 

 

➤ 단방향 연관 관계

 

한 쪽 클래스만 다른 쪽 클래스의 참조 정보를 가지고 있는 관계

 

 

➤ 양방향 연관 관계

 

양 쪽 클래스 모두 서로의 객체를 참조 정보를 가지고 있는 관계

 

JPA는 단방향, 양방향 연관 관계 모두 지원하지만 Spring Data JDBC는 단방향 연관 관계만 지원한다.

 

 

➤ 일대다(1:N) 단방향 연관 관계

 

일(1)에 해당하는 클래스가 다(N)에 해당하는 객체를 List 등을 사용해서 참조할 수 있다.

일대다 단방향 매핑은 잘 사용하지 않는다.

 

 

➤ 다대일(N:1) 연관 관계

 

다(N)에 해당하는 클래스가 일(1)에 해당하는 객체를 참조할 수 있는 관계를 의미한다.

 

▶️ @ManyToOne

 

  • 이 애너테이션으로 다대일 관계를 명시한다.
  • @JoinColumn(name = “MEMBER_ID”)
    • 매핑하는 테이블의 외래키(부모 테이블의 기본키)에 해당하는 칼럼명을 적어준다.

 

 

➤ 일대다(1:N) 연관 관계

 

다대일 연관관계를 설정한 이후에 자식 테이블에도 일대다 관계를 만들어줘서 양방향 관계를 만들어 준다.

 

 

▶️ @OneToMany

 

  • 이 애너테이션을 부모테이블에 추가하여 일대다 관계를 만들어준다.

Attribute

  • mappedBy
    • 값은 관계를 소유하고 있는 필드(N(다)에 해당하는 필드)를 지정한다.
    • mappedBy는 참조할 대상이 있어야 한다.
    • 일대다 단방향 매핑의 경우에는 필요하지 않다.

 

 

➤ 다대다(N:N) 연관 관계

 

다대다는 관계는 중간에 테이블을 하나 추가해서 두 개의 일대다 관계로 만들어주는 것이 일반적이다.

 

 

➤ 엔티티 간의 연관 관계 매핑 권장 방법

 

  • 일대다 매핑은 사용하지 않는다.
  • 제일 먼저 다대일 단방향 매핑부터 적용한다.
  • 다대일 단방향 매핑을 통해 객체 그래프 탐색으로 조회할 수 없는 정보가 있을 경우, 양방향 매핑을 적용한다.

 

 

 

➤ Cascading

 

부모테이블에서 자식테이블로 데이터의 상태 변화를 전파(?)할 때 사용한다.

JPA javax.persistence.CacadeType 에 정의되어 있다.

부모 테이블의 @OneToMany 애너테이션에 Attribute로 추가한다.

 

@OneToOne(mappedBy = "member", cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
private Stamp stamp;

 

Attribute

  • ALL
  • PERSIST
  • MERGE
  • REMOVE
  • REFRESH
  • DETACH

 

 

 

 

읽어주셔서 감사합니다.

오개념에 대한 지적은 늘 환영입니다. 😄

 

 

 

 

 

 

 

 

 

JPA(Java Persistence API)란?

 

 

➤ JPA(Java Persistence API)란?

 

  • ORM(Object-Relation Mapping) 기술의 표준 사양(또는 명세, Specification)
  • Java의 인터페이스로 사양이 정의되어 있고 JPA라는 표준 사양을 구현한 구현체는 따로 있다.

 

 

➤ Hibernate ORM

 

  • JPA 표준 사양을 구현한 구현체 : Hibernate ORM, EcliipseLink, DataNucleus
  • Hibernate ORM은 JPA에서 정의해둔 인터페이스를 구현한 구현체 중 하나이다.
  • JPA에서 지원하는 기능 이외에도 자체적으로 사용하도록 지원하는 API 도 있다.

 

 

※ Jakarta Persistence

 

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

2019년에 나온 JPA 3.0 버전 부터 Jakarta Persistence 라는 이름으로 바뀌었다.

Jakarta Persistence 라고 바뀌면서 패키지와 속성도 javax.persistence 에서 jakarta.persistence 로 이름이 바뀌었다.

엔터프라이즈 Java 애플리케이션에서 관계형 데이터 관리를 설명하는 Jakarta EE 애플리케이션 프로그래밍 인터페이스 사양(specification)이다.

 

 

 

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

 

 

 

데이터 액세스 계층에서 JPA는 상단에 위치한다.

데이터 저장, 조회 등의 작업은 JPA를 거쳐 JPA의 구현체인 Hibernate ORM을 통해서 이뤄진다.

Hibernate ORM은 내부적으로 JDBC API를 이용해서 데이터베이스에 접근한다.

 

 

 

➤ JPA(Java Persistence API)에서 P(Persistence)의 의미

 

Persistence는 영속성, 지속성이라는 뜻이다.

그렇다면 무엇을 지속시키는 것일까?

엔티티 객체 정보를 지속시킨다는 의미이다.

 

 

▶️ 영속성 컨텍스트(Persistence Context)

 

영속성 컨텍스트(Persistence Context)

 

ORM(Object-relational-mapping)은 객체(Object)와 데이터베이스 테이블의 매핑을 통해 엔티티 클래스 객체 안에 포함된 정보를 테이블에 저장하는 기술이다.

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

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

 

 

JPA API 중 엔티티 정보를 영속성 컨텍스트에 저장(persist)하는 API를 사용하면 영속성 컨텍스트의 1차 캐시에 엔티티 정보가 저장된다.

 

 

JPA 영속성 컨텍스트

  • EntityManager 클래스에 의해서 관리된다. -> EntityManagerFactory 객체를 Spring으로부터 DI 받을 수 있다.
  • EntityManagerFactory의 createEntityManager() 메서드를 이용해서 EntityManager 객체를 얻을 수 있다. -> JPA API 메서드 사용 가능
  • persist() 메서드: 영속성 컨텍스트에 객체의 정보들이 저장된다.
  • 저장되었는지 확인하려면 find(조회할 엔티티 클래스의 타입, 조회할 엔티티 클래스의 식별자 값) 메서드 사용

 

 

 

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

 

 

▶️ JPA API를 사용하기 위한 사전 준비

 

 

✅ build.gradle 설정

 

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'com.h2database:h2'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

 

Spring Data JPA 기술을 포함한 JPA API를 사용할 수 있다.

 

 

✅ application.yml에 아래 코드 추가

jpa:
	hibernate:
		ddl-auto: create  # (1) 스키마 자동 생성
	show-sql: true      # (2) SQL 쿼리 출력

 

※ yml에서 추가한 코드가 제대로 적용되지 않을 때는 공백 레벨을 잘 확인해보자.

 

Spring Data JDBC에서는 schema.sql 파일에 테이블 생성을 위한 스키마를 직접 작성해주어야 하지만 JPA는 (1)의 코드 하나를 추가함으로써 JPA가 자동으로 데이터베이스에 테이블을 생성해 준다.

 

 

▶️ @GeneratedValue

 

식별자를 생성해주는 전략을 지정할 때 사용

이 애너테이션을 엔티티의 멤버 변수에 추가하면 데이터베이스 테이블에서 기본키가 되는 식별자를 자동으로 설정해준다.

 

 

▶️ 영속성 컨텍스트에 저장하기

 

persist() 를 호출 -> 1차 캐시에 객체가 저장되고, 객체가 쓰기 지연 SQL 저장소에 INSERT 쿼리 형태로 등록이 된다.

영속성 컨텍스트에 객체를 저장하지만 실제 테이블에 정보를 저장하지는 않는다.

 

JPA가 내부적으로 테이블을 자동으로 생성하고, 테이블의 기본키를 할당해준다.

 

 

▶️ 데이터베이스 테이블에도 데이터 저장하기

 

EntityManagergetTrancsation() 메서드를 이용하여 Transaction 객체를 얻는다.

(JPA에서는 Transaction 객체를 기준으로 DB 테이블에 데이터를 저장한다.)

Transaction을 시작하기 위해서 begin() 메서드 사용

➡️ persist() 로 객체를 영속성 컨텍스트에 저장

➡️ commit() 메서드 호출하여 영속성 컨텍스트에 저장되어 있는 객체를 DB 테이블에 저장한다.

 

 

✔️ persist() : 영속성 컨텍스트의 1차 캐시에 엔티티 클래스의 객체가 저장 + ‘쓰기 지연 저장소’에 INSERT 쿼리가 등록

✔️ commit() : ‘쓰기 지연 SQL 저장소’에 등록된 모든 INSERT 쿼리가 실행 + 실행된 INSERT 쿼리는 쓰기 지연 SQL 저장소에서 제거됨

✔️ find() : 1차 캐시에서 해당 객체가 있는지 조회하고, 없으면 테이블에 SELECT 쿼리를 전송해서 조회

 

 

 

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

 

find() 메서드로 1차 캐시에 저장된 객체를 불러와서 객체에 setter로 데이터를 변경

commit() 메서드로 SQL 저장소에 등록된 UPDATE 쿼리가 실행된다.

 

✅ setter 메서드로 값을 변경만 해도 commit() 시점에 UPDATE 쿼리가 실행되는 이유?

영속성 컨텍스트에 엔티티가 저장될 경우 저장되는 시점의 상태를 그대로 가지고 있는 스냅샷을 생성한다.

그 후 엔티티의 값을 setter 메서드로 변경한 후, commit()을 하면 변경된 엔티티와 이전에 이미 떠 놓은 스냅샷을 비교한 후 변경된 값이 있으면 쓰기 지연 SQL 저장소에 UPDATE 쿼리를 등록하고 UPDATE 쿼리를 실행

 

 

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

 

EntityManager의 remove() 메서드를 통해 1차 캐시에 있는 엔티티를 제거하도록 요청

Transaction의 commit() 을 실행하면 영속성 컨텍스트에 1차 캐시에 있는 엔티티를 제거하고, 쓰기 지연 SQL 저장소에 등록된 DELETE 쿼리가 실행된다.

 

 

 

▶️ EntityManager의 flush() API

 

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

 

 

 

※ 추가로 학습해야할 자료들

 

JPA와 Hibernate 에서 Entity Lifecycle Model

https://thorben-janssen.com/entity-lifecycle-model/

 

Entity Lifecycle Model in JPA & Hibernate

The entity lifecycle model is one of the core concepts of JPA. It defines if an entity gets loaded, if changes get persisted, and much more

thorben-janssen.com

 

 

 

 

읽어주셔서 감사합니다.

오개념에 대한 지적은 언제나 환영입니다. 😄

 

1