beadss / jpa-study

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

4장 요약 #7

Open joont92 opened 5 years ago

joont92 commented 5 years ago

@Entity

JPA가 관리하는 엔티티가 되기 위해서 필수로 붙여야 하는 어노테이션이다.

속성

속성 기능 기본값 메모
name JPA에서 사용할 엔티티 이름 지정. 중복되는 이름이 있어선 안된다. 클래스 이름 그대로 사용(e.g. Member) 근데 얘를 어디서 쓰는걸까

엔티티가 될 클래스에는 몇가지 룰이 존재한다.

이 3가지 조건이 붙은 이유는 왜 일까?
동작방식과 깊이 연관되어 있을텐데, 궁금하다..
기본 생성자는 없어도 따로 오류가 발생하지 않던데.. JPA 어디서 사용한다는건지?

https://stackoverflow.com/questions/3472438/why-cant-entity-class-in-jpa-be-final
https://www.objectdb.com/java/jpa/entity/types

@Table

엔티티와 매핑할 테이블을 지정할 때 사용한다. 생략하면 엔티티 이름을 테이블 이름으로 사용한다.

속성

속성 기능 기본값 메모
name 매핑할 테이블 이름 엔티티 이름
uniqueConstraints(DDL) DDL 생성 시에 unique constraints 만듬. 2개 이상의 복합 unique constrains도 가능

기본 키 매핑

@Id 어노테이션을 사용해서 프로퍼티의 기본키를 지정해줘야 한다. 알다시피, 필수값이다.

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

@Id 적용 가능한 타입은 아래와 같다.

기본키 생성 전략

엔티티의 기본키를 설정하는 방법에는 크게 직접할당자동생성이 있다.

직접할당은 말 그대로 기본키 값을 애플리케이션에서 직접 할당하는 방법이다.

자동생성의 경우 직접할당과 반대로 데이터베이스에 의존하는 방식이다.
@GeneratedValue 어노테이션 + 전략 설정이 필요하다.

  1. IDENTITY 전략 MYSQL의 AUTO_INCREMENT와 같다고 보면 된다.
    아래와 같이 선언해주면 된다.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

row insert시에 데이터베이스가 자동으로 생성해주는 기본 키 값을 사용하는 방식이다.
이 말인 즉 데이터베이스에 직접 insert 하는 작업이 선행되어야 한다는 뜻이므로,
JPA의 쓰기지연이 동작하지 않는다는 의미이다.

원래라면 insert한 뒤에 추가로 select로 기본 키 값을 SELECT 해오는데,
하이버네이트는 JDBC3 부터 추가된 Statement,getGeneratedKeys()(저장과 동시에 생성된 기본 키 값을 얻어오는 메서드)를 사용함으로써 데이터베이스와 한번만 통신한다(최적화)

  1. SEQUENCE 전략 ORACLE의 SEQUENCE와 같다고 보면 된다.
    기본적으로 SEQUENCE가 생성되어 있어야한다. 그리고 아래와 같이 선언해주면 된다.
@Entity
@SequenceGenerator(
    name = "BOARD_SEQ_GENERATOR", // 사용할 sequence 이름
    sequenceName = "BOARD_SEQ", // 실제 데이터베이스 sequence 이름
    initialValue = 1, allocationSize = 1
)
public class Board{
    @Id
    @GeneratedValue(
        strategy = GenerationType.SEQUENCE,
        generator = "BOARD_SEQ_GENERATOR" // 위의 sequence 이름
    )
    private Long id;
}

이제 id 식별자 값을 얻어올 때 마다 BOARD_SEQ 시퀀스를 사용하게 된다.
참고로 SEQUENCE 전략은 insert를 선행할 필요없이 sequence에서 nextVal을 읽어오기만 하면 되므로,
쓰기지연을 사용할 수 있다.

위의 @SequenceGenerator를 보면 initialValue, allocationSize라는 것이 있다.

initialValue는 sequence 초기값을 설정할 떄 사용하는 옵션인데, 이말인 즉 sequence도 미리 생성해놓지 않으면 자동 생성 가능하다는 것이다(DDL 자동생성을 on 하면 됨)

allocationSize는 시퀀스 한번 호출에 증가하는 수이다.
default 값이 50인데, 이는 최적화를 위해서이다. 1~50까지의 sequence 값을 한번에 받고 메모리에 저장해서 할당해주다가, 51번째 sequence가 필요할 떄 데이터베이스 sequence에서 51~100의 sequence를 조회해오는 식으로 동작한다.

  1. TABLE 전략 sequence를 흉내내는 전략이다. table을 하나 만들어 name과 sequence 값을 저장해둔다.
    table을 사용하므로 모든 데이터베이스에서 사용 가능하다. 사용법은 sequence와 거의 동일하다.
@Entity
@TableGenerator(
    name = "MY_BOARD_SEQ_GENERATOR", // 사용할 sequence 이름
    table = "MY_BOARD_SEQ", // 실제 데이터베이스 sequence 이름
    pkColumnValue = "BOARD_SEQ", allocationSize = 1
)
public class Board{
    @Id
    @GeneratedValue(
        strategy = GenerationType.TABLE,
        generator = "MY_BOARD_SEQ_GENERATOR" // 위의 sequence 이름
    )
    private Long id;
}

기본적으로 테이블은 sequence_name, next_val 의 컬럼을 가진 형태로 생성되고, 로우의 내용은 아래와 같다.
(이름이 맘에 안들면 pkColumnName=XXX, valueColumnName=XXX 의 형태로 지정해주면 된다.)

sequence_name next_val
BOARD_SEQ 2
MEMBER_SEQ 7
PRODUCT_SEQ 50

보다시피 하나의 테이블로 관리하므로, pkColumnValue로 어떤 sequence_name을 사용할지 지정해줘야 한다.

  1. AUTO 전략 선택한 데이터베이스 dialect에 따라 전략(IDENTITY, SEQUENCE, TABLE)을 자동으로 선택해주는 방식이다.
    예를 들면 오라클은 SEQUENCE, MYSQL은 IDENTITY가 선택된다.
    @GeneratedValue의 기본값은 AUTO이다.

식별자 권장 전략
기본키의 형태는 크게 자연키(비즈니스 의미가 있는 키. e.g. 주민등록번호)
와 대리키(임의로 만들어진 키)가 있는데, 외부풍파에 쉽게 흔들리지 않는 대리키를 사용하는 것아 좋다.
비즈니스라는 것은 내 생각보다 훨씬 쉽게 변하기 때문이다.

필드 매핑

@Column

객체를 필드 테이블에 매핑할 때 사용한다. 가장 많이 사용된다.

속성 기능 기본값
name 필드와 테이블 이름 매핑 객체 필드 이름
nullable(DDL) null 값 허용 여부. false 설정하면 DDL 생성 시 not null이 붙는다 true
unique(DDL) 컬럼 하나에 unique constraints 걸때 사용. 여러개 걸려면 @Table의 uniqueConstraints를 사용해야 함
length(255) 문자 길이 제약조건. 명시적으로 길이를 볼 수 있는 장점도 있다 255

@Column을 생략해도 엔티티의 필드는 전부 자동으로 테이블과 매핑된다.
이 때 몇가지 특징이 있다.

  1. 이름은 어떻게 매핑되는가?
    @Column의 기본값과 동일하게 컬럼명으로 사용된다. 근데 여기서 딜레마가 하나 있다.
    java는 naming을 관례적으로 camel case를 사용하고, database는 naming을 관례적으로 under score를 사용한다는 것이다.
    이떄 persistence.xml에

    <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"></property>

    전략을 주게 되면 위의 딜레마를 해결 가능하다(서로간에 자동 변환)

  2. nullable 속성

    
    int id; // not null로 생성됨. primitive에는 null이 들어갈 수 없기 때문.

Integer id; // nullable true로 생성됨

@Column int id; // @Column의 기본값인 nullable=true가 적용되서 nullable=true로 생성됨. 주의해야함


### @Enumerated
java의 enum 타입을 매핑할 때 사용된다. 유용하게 사용 가능하다.  

```java
@Enumerated(EnumType.STRING)
private RoleType roleType;

이렇게 주면 enum의 값 그대로(문자열) 데이터베이스에 저장된다.
ORDINAL을 속성을 사용하면 enum의 순서대로 index가 데이터베이스에 저장되는데,
유연하지 못하므로 STRING 속성을 사용하는 것이 낫다.

@Temporal

날짜 타입을 매핑할 때 사용된다.

@Temporal(TemporalType.DATE)
private Date date; // date date 생성

@Temporal(TemporalType.TIME)
private Date time; // time time 생성

@Temporal(TemporalType.TIMESTAMP)
private Date timestamp; // timestamp timestamp 생성

TemporalType은 필수로 지정해야 한다.

@Lob

BLOB, CLOB 타입에 매핑된다.

@Lob
String lob; // CLOB으로 매핑. mysql에선 longtext로 생성됨

@Lob
byte[] lob; // BLOB으로 매핑. mysql에선 longblob으로 생성됨

@Transient

매핑하지 않을 필드에 설정한다. 임의로 값을 보관하고 싶을때 등에 사용한다.