beadss / jpa-study

jpa슽터디입니다
1 stars 2 forks source link

4장 요약 정리 #8

Open remagine opened 5 years ago

remagine commented 5 years ago

4 엔티티 맵핑

  1. 객체 - DB 간 어노테이션 맵핑

1.1 @Entity

또한 JPA는 엔티티 객체 생성에 기본 생성자를 사용하므로, 기본 생성자를 생성하도록 하는 것이 좋다

1.2 @Table

@Entity(name="Member")  
@Table(name="MEMBER", uniqueConstraints = { @UniqueConstraint( //추가
name = "NAME_AGE_UNIQUE",
columnNames {"NAME", "AGE"} )})

public class Member {
 @Id  
 @Column(name = "id")
 private String id;

 @Column(name = "name")
 private String username;

 private Integer age;

 ...

1.3 @Id

기본키는 직접할당 , 자동생성 방식이 있다. 직접할당 : 어플리케이션에서 입력 자동생성 : 대리키 사용방식

자동생성 방식은 @GeneratedValue에 원하는 생성방식을 지정하면 된다. 또한 기본키의 적용 가능한 자바타입은 기본형, 래퍼형, String , Date, BigDecimal, BigInteger가 있다. 여러 필드를 포함하는 클래스는 안된다는 의미

1.3.1 IDENTITY 전략 @GeneratedVale(strategy = GenerationType.IDENTITY)

엔티티가 영속화 되려면 식별자(id,pk,키)값이 반드시 필요하다.

IDENTITY 전략은 DB에게 ID값을 위임하므로 , JPA는 DB에서 조회하기 전에는 ID값을 알 수 없다. 그러므로 IDENTITY 전략을 사용하는 ENTITY는 persist() 영속화 즉시, insert를 실행하여 id값을 가져온다. 따라서 이 전략은 트랜잭션을 지원하는 쓰기 지연이 동작하지 않는다.

jdbc3에 추가된 Statement.getGeneratedKeys()를 사용하면 데이터를 저장하면서 동시에 생성된 키값을 얻어올 수 있으므로 DB 조회 쿼리를 1번만 수행해도 되는 장점이 있다.

1.3.2 SEQUENCE 전략

POSTGRES, 오라클 등에서 사용한 전략으로 사실 이것만 써봄

먼저 DB에서 시퀀스를 생성하고 해당 시퀀스 명을 전략에 맵핑하면된다.

@Entity
@SequenceGenerator(
    name = "BOARD SEQ GENERATOR", 
    sequenceName = "BOARD_SEQ", //매핑할데이터베이스 시퀀스 이름
    initialValue = 1, allocationSize = 1)
public class Board (
    @Id  
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
                generator = "BOARD_SEQ_GENERATOR")
    private Long id;
    ...

다소 귀찮은게 JPA의 시퀀스 제너레이터 명과 DB의 시퀀스 명이 구분되고 있다는 점. 보통 프로젝트마다 후미구를 지정하여 구분한다.

시퀀스 전략은 먼저 시퀀스에서 ID값을 조회한 후 영속성객체에 저장한다.

IDENTITY 전략은 ID값 생성을 위해 INSERT를 먼저해야했다는 점에서 차이가 있다. (LAZYLOADING이 가능하고 아니고의 차이)

시퀀스 전략과 최적화

JPA는 시퀀스에 접근하는 횟수를 줄이기 위해 allocationSize를 사용한다.

최적화 방법 원리 이해 불가 토의필요

1.3.3 Table 전략

테이블을 마치 시퀀스처럼 활용하는 전략이다.

CREATE TABLE MY_SEQUENCE{
 SEQUENCE_NAME VARCHAR(255) NOT NULL,
 NEXT_VAL BIGINT,
 PRIMARY KEY (SEQUENCE_NAME)
}

동작방식은 시퀀스 방식과 같고, 시퀀스 네임별로 next_val이 증가하는 방식이긴한데

만일 여러머신에서 동시에 접근한다면? next_val이 중복될 가능성은 없는가??

select로 id값 조회 후 , 바로 update로 nextval을 증가시킨다. 트랜잭션으로 관리되므로 중복될 이유는 없다.

역시 최적화 방식은 아직 이해가 잘 되지 않는다

1.3.4 AUTO 전략

데이터베이스에 따라 알아서 전략을 선택해준다. 오라클은 시퀀스, MYSQL은 IDENTITY

궁금한 점은 AUTO로 설정된 ID전략이 알아서 시퀀스명을 찾아주는 지 ?

내 기억에 auto로 설정하면, db에서 시퀀스 생성시 auto로 생성되는 name값을 찾아주는 것으로 기억하는데 가물가물

참고자료

자연키보다 대리키 사용이유 p144

  1. 필드와 컬럼맵핑

@Column

int data1; // @Column 생략, 자바 기본 타입 -> 기본 타입에는 null을 입력할 수 없으므로 not null이다. JPA가 DDL 생성기능을 사용할 때 자동으로 not null 제약조건을 추가한다.
data1 interger not null // 생성된 DDL

Integer data2; // @Column 생략, 객체 타입 -> null 가능
data2 integer // 생성된 DDL

@Column
int data3; // @Column 사용시 nullable=true 가 기본 값이므로, 자바 기본 타입에 @Column을 사용하는 경우 nullable=false로 지정하는 것이 안전하다. 
data3 integer; // 생성되는 DDL

jpa, 하이버네이트는 기본형을 래퍼클래스로 하는 경향이 있는데 이는 nullable때문인듯 하다

2.1 레퍼런스 정리

2.1.1 @Enumerated EnumType.ORDINAL : enum 순서를 데이터베이스에 저장(0부터) EnumType.STRING : enum 이름을 데이터베이스에 저장(권장한다)

@Enumerated(EnumType.STRING) private RoleType roleType;

주로 String 전략을 사용한다.

2.1.2 @Temporal

날짜형식을 저장할 때 사용한다.

MYSQL : datetime 오라클 , 포스트그레스 : timestamp

@Temporal(TemporalType.DATE)
private Date date; // 날짜 2015-01-01

@Temporal(TemporalType.TIME)
private Date time; // 시간 11:11:11

@Temporal(TemporalType.TIMESTAMP)
private Date timestamp; // 날짜와 시간 2015-01-01 11:11:11

// 생성되는 DDL
date date,
time time,
timestamp timestamp,

java8의 로컬데이트타입은 interface를 통해 형변환이 필요하다.

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.sql.Timestamp;
import java.time.LocalDateTime;

@Converter(autoApply = true)
public class LocalDateTimeAttributeConverter implements AttributeConverter<LocalDateTime, Timestamp> {

    @Override
    public Timestamp convertToDatabaseColumn(LocalDateTime locDateTime) {
        return (locDateTime == null ? null : Timestamp.valueOf(locDateTime));
    }

    @Override
    public LocalDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
        return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDateTime());
    }
}

위와같이 converter를 구현하면 해당 형에 대한 형변환이 자동으로 이뤄진다.

2.1.3 @Lob