본문 바로가기

Advance I/Springboot & JPA

22.05.30

플러시 (flush)

영속성 컨텍스트의 변경내용을 데이터베이스에 반영

• 변경 감지

• 수정된 엔티티 쓰기 지연 SQL 저장소에 등록

• 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송 (등록, 수정, 삭제 쿼리)

 

영속성 컨텍스트를 플러시하는 방법

• em.flush() - 직접 호출

• 트랜잭션 커밋 - 플러시 자동 호출

• JPQL 쿼리 실행 - 플러시 자동 호출

 

*플러시를 해도 1차 캐시는 유지된다. 1차 캐시는 엔티티 매니저, 즉 트랜잭션 단위이다.

*persist를 호출했을 때 DB에 데이터가 바로 저장되는 것이 아닌데, 플러시 호출 전에 JPQL로 데이터를 조회하려고 하면 DB에 존재하지 않는 데이터를 참조하려고 할 수 있다. 그런 상황을 방지하고자 JPQL 쿼리 실행시 플러시가 호출된다.

 

플러시 모드 옵션

• FlushModeType.AUTO: 커밋이나 쿼리를 실행할 때 플러시 (기본값)

• FlushModeType.COMMIT: 커밋할 때만 플러시. 보통은 큰 이점이 없기 때문에 AUTO로 쓰자.

 

플러시는!

• 영속성 컨텍스트를 비우지 않음

• 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화

• 트랜잭션이라는 작업 단위가 중요 -> 커밋 직전에만 동기화 하면 됨

 

준영속 상태

영속 상태: 엔티티가 1차 캐시에 올라온 상태. em.persist, em.find 등

준영속 상태: 영속 상태의 엔티티가 영속성 컨텍스트에서 분리(detached). 영속성 컨텍스트가 제공하는 기능을 사용 못함

 

em.find 메서드에 의해 엔티티를 조회하는 쿼리 O = select query O

setName을 통한 데이터 변경 감지 (dirty check) X  = update query X

=> 트랜잭션 커밋 전 해당 엔티티가 준영속 상태가 되었기 때문에

 

준영속 상태로 만드는 방법

• em.detach(entity): 특정 엔티티만 준영속 상태로 전환. 1차 캐시 내 특정 엔티티를 지움. 

• em.clear(): 영속성 컨텍스트를 완전히 초기화. 1차 캐시를 비움

• em.close(): 영속성 컨텍스트를 종료

 

*데이터베이스에 저장된 엔티티에는 영향 없음.

*준영속 상태의 엔티티를 조회하면 다시 DB에 쿼리를 해서 1차 캐시에 저장하여 영속상태가 된다. 

*사실상 1차 캐시가 영속성 컨텍스트

 

04. 엔티티 매핑

엔티티 매핑 소개

• 객체와 테이블 매핑: @Entity, @Table

• 필드와 컬럼 매핑: @Column

• 기본 키 매핑: @Id

• 연관관계 매핑: @ManyToOne, @JoinColumn

 

객체와 테이블 매핑

@Entity

• @Entity가 붙은 클래스는 JPA가 관리, 엔티티라 한다.

• JPA를 사용해서 테이블과 매핑할 클래스는 @Entity 필수

 

< 주의 >

• 기본 생성자 필수(파라미터가 없는 public 또는 protected 생성자)   *reflection, proxing 등에 필요

• final 클래스, enum, interface, inner 클래스 사용X

• 저장할 필드에 final 사용 X

 

속성

• name

  - JPA에서 사용할 엔티티 이름을 지정한다.

  - 기본값: 클래스 이름을 그대로 사용(예: Member) 

  - 동일한 클래스 이름이 없으면 가급적 기본값을 사용한다.

 

@Table

• @Table은 엔티티와 매핑할 테이블 지정

 

속성

• name: 매핑할 테이블 이름 (기본값: 엔티티 이름)

• catalog: 데이터베이스 catalog 매핑

• schema: 데이터베이스 schema 매핑

• uniqueConstraints(DDL): DDL 생성 시에 유니크 제약 조건 생성

 

※ 데이터베이스 스키마 자동 생성

개발 장비에서만 사용

엔티티 객체 매핑을 해두면 애플리케이션 실행 시점에 테이블을 자동으로 생성한다.

데이터베이스 방언(같은 기능, 다른 명령어)을 활용해서 데이터베이스에 맞는 적절한 DDL을 생성한다.

<property name="hibernate.hbm2ddl.auto" value="create" />

속성(value)

• create: 기존테이블 삭제 후 다시 생성 (DROP + CREATE)

• create-drop: create와 같으나 종료시점에 테이블 DROP

• update: 변경분만 반영. DROP이 아닌 ALTER. 추가와 수정만 가능. 삭제는 불가

• validate: 엔티티와 테이블이 정상 매핑되었는지만 확인

• none: 사용하지 않음. 실제는 없는 옵션으로, 해당 옵션이 없기 때문에 실행이 안되는 것과 같은 결과.

 

* 주의 *

• 운영 장비에는 절대 create, create-drop, update 사용하면 안된다.

• 개발 초기 단계는 create 또는 update

• 테스트 서버(다수 개발자가 사용)는 update 또는 validate 

• 스테이징과 운영 서버는 validate 또는 none

 

*로컬에서는 자유롭게 사용하나, 테스트 서버부터는 가급적 사용하지 않는 것이 좋다.

UPDATE를 사용하더라도, ALTER TABLE 이 되는 동안 데이터베이스가 lock이 걸려서 서비스가 멈출 수 있다.

 

DDL 생성 기능

• 제약조건 추가

 ex. 회원 이름은 필수, 10자 초과X  -> @Column(nullable = false, length = 10)

• 유니크 제약조건 추가

 ex. @Table(uniqueConstraints = {@UniqueConstraint( name = "NAME_AGE_UNIQUE",

                                                                                          columnNames = {"NAME", "AGE"} )})

*DDL 생성 기능은 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다. 따라서 스키마 자동 생성 기능을 사용하지 않고 직접 DDL을 만든다면 사용할 이유가 없다. 이 기능을 사용하면 애플리케이션 개발자가 엔티티만 보고도 손쉽게 다양한 제약조건을 파악할 수 있는 장점이 있다.

 

필드와 컬럼 매핑

@Column: 컬럼 매핑

@Column 의 속성

유니크 제약조건은 컬럼에 직접 부여하기 보다 @Table을 통해서 많이 사용한다.

columnDefinition은 특정 DB에 종속적인(방언) 옵션에 사용한다.

 

@Enumerated: enum 타입 매핑

속성(value)

• EnumType.ORDINAL: enum 순서를 데이터베이스에 저장

• EnumType.STRING: enum 이름을 데이터베이스에 저장

(기본값: EnumType.ORDINAL / 권장:  EnumType.STRING)

 

@Temporal: 날짜 타입 매핑

Date, Calendar 타입에 사용

*참고: LocalDate, LocalDateTime을 사용할 때는 생략 가능(최신 하이버네이트 지원)

 

속성(value)

• TemporalType.DATE: 날짜, 데이터베이스 date 타입과 매핑 (예: 2013–10–11)

• TemporalType.TIME: 시간, 데이터베이스 time 타입과 매핑 (예: 11:11:11)

• TemporalType.TIMESTAMP: 날짜와 시간, 데이터베이스 timestamp 타입과 매핑(예: 2013–10–11 11:11:11)

 

@Lob: BLOB, CLOB 매핑 (비구조화 대형 객체)

• 매핑하는 필드 타입이 문자면 CLOB 매핑, 나머지(이진)는 BLOB 매핑

• 속성 없이 자동으로 타입을 지정해준다.

• CLOB: String, char[], java.sql.CLOB

• BLOB: byte[], java.sql.BLOB

 

@Transient: 특정 필드를 컬럼에 매핑하지 않음(매핑 무시)

데이터베이스와 무관. 메모리에서만 사용

 

기본 키 맵핑

@Id @GeneratedValue(strategy = GenerationType.AUTO)

private Long id;

@Id: 기본키 지정

• Id 값 직접 할당 시 @Id만 사용

@GeneratedValue: 기본키 값 자동 생성

  strategy

  1. IDENTITY

데이터베이스에 위임, MYSQL. 영속성 컨텍스트에 의해 관리되려면 반드시 id 값이 있어야 한다. 그러나 트랜잭션 커밋 시점에 INSERT SQL 실행 한 이후에야 ID 값을 알 수 있기 때문에, IDENTITY 전략은 em.persist() 시점에 즉시 쿼리를 실행 하고 DB에서 식별자를 조회한다. 즉, persist 시점에 Id 필드 값이 채워진다.

 

  2. SEQUENCE

유일한 값을 순서대로 생성하는 데이터베이스 시퀀스 오브젝트 사용, ORACLE. @SequenceGenerator가 필요하며 테이블(엔티티)마다 시퀀스 오브젝트를 다르게 생성하여 매핑할 수 있다. em.persist() 시점에 시퀀스 오브젝트에 다음 시퀀스를 요청하여 id 필드를 채운다. INSERT SQL은 트랜잭션 커밋 시점에 호출된다. 즉, 네트워크를 2번 탐.

@Entity
@SequenceGenerator(
        name = “MEMBER_SEQ_GENERATOR", 
        sequenceName = “MEMBER_SEQ", //매핑할 데이터베이스 시퀀스 이름
        initialValue = 1, allocationSize = 1)
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
            generator = "MEMBER_SEQ_GENERATOR")
    private Long id; 
    ...

 

  3. TABLE

데이터베이스 시퀀스를 흉내내는 키 생성용 테이블 사용, 모든 DB에서 사용. @TableGenerator 필요

@Entity
@TableGenerator(
        name = "MEMBER_SEQ_GENERATOR",
        table = "MY_SEQUENCES",
        pkColumnValue = “MEMBER_SEQ", allocationSize = 1) 
        public class Member {
        @Id
        @GeneratedValue(strategy = GenerationType.TABLE,
                generator = "MEMBER_SEQ_GENERATOR")
        private Long id;
        ...

을 실행하면 DB 내에 키 생성용 테이블로 지정한 MY_SEQUENCES 라는 이름의 테이블이 생성된다.

sequence_name(pk) = 시퀀스 컬럼명, next_val = 시퀀스 값

create table MY_SEQUENCES (
    sequence_name varchar(255) not null,
    next_val bigint,
    primary key ( sequence_name )
    )

 

  4. AUTO

데이터베이스 방언에 따라 IDENTITY, SEQUENCE, TABLE 중 자동 지정, 기본값

 

 ***SEQUENCE, TABLE의 성능 최적화***

allocationSize 속성(기본값:50)을 사용할 수 있다. 동시성 문제 없이 한 번 시퀀스 오브젝트를 호출할 때 allocationSize 만큼의 시퀀스를 받아와서 메모리 상에서 사용한다. 

 

권장하는 식별자 전략

• 기본 키 제약 조건: null 아님, 유일, 변하면 안된다.

• 미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. 대리키(대체키)를 사용하자.

• 예를 들어 주민등록번호도 기본 키로 적절하기 않다.

• 권장: Long형 + 대체키 + 키 생성전략 사용

 

*대체키: 테이블에서 입력 데이터의 어떤 열(자연키)이 아닌 시스템쪽에 독립적으로 할당된 키

 

<Database Language>

- DDL(Data Definition Language)

테이블과 같은 데이터 구조를 정의하는데 사용되는 명령어. CREATEALTER, DROP, RENAME, TRUNCATE

- DML(Data Manipulation Language)

데이터베이스에 들어 있는 데이터에 대해 조회, 검색, 변형을 위한 명령어. SELECT, INSERT, UPDATE, DELETE

- DCL(Data Control Language)

데이터베이스에 접근하고 객체들을 사용하도록 권한을 주고 회수하는 명령어. GRANT, REVOKE

- TCL(Transaction Control Language)

DML에 의해 조작된 결과를 작업단위(트랜잭션) 별로 제어하는 명령어. COMMIT, ROLLBACK, SAVEPOINT 

 

'Advance I > Springboot & JPA' 카테고리의 다른 글

22.06.02  (0) 2022.06.02
22.06.01  (0) 2022.06.02
22.05.29  (0) 2022.05.29
22.05.28  (0) 2022.05.28
22.05.26 :: 자바 ORM 표준 JPA 프로그래밍 - 기본편  (0) 2022.05.28