자바 ORM 표준 JPA 프로그래밍, 하단의 블로그, 김영한의 실전 JPA1을 참고해서 정리한 글입니다!

 

 

[JPA] 엔티티와 매핑. @Entity, @Table, @Id, @Column..

| 엔티티와 매핑 객체와 테이블 매핑 : @Entity, @Table 기본 키 매핑 : @Id 필드와 컬럼 매핑 : @Column 연관관계 매핑 : @ManyToOne, @JoinColumn 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23..

data-make.tistory.com

1. 엔티티

- 테이블과 매핑

- @Entity가 붙은 클래스는 JPA가 관리하는 것으로 엔티티라고 불림

 

* 속성

Name : JPA에서 사용할 엔티티 이름을 지정. 보통 기본값인 클래스 이름 사용

 

* 주의사항

- 기본 생성자는 필수 (JPA가 엔티티 객체 생성 시 기본 생성자 사용)

- final 클래스, enum, interface, inner class에는 사용 불가

- 저장할 필드에 final 사용 불가

 

2. 테이블

- 엔티티와 매핑할 테이블 지정

- 생략시 매핑한 엔티티 이름을 테이블 이름으로 사용

 

* 속성

Name: 매핑할 테이블 이름 (default, 엔티티 이름 사용)

Catalog: catalog 기능이 있는 DB에서 catalog를 매핑 (default, DB명)

Schema: schema 기능이 있는 DB에서 schema를 매핑

uniqueConstraints: DDL 생성 시 유니크 제약 조건을 만듦. 스키마 자동 생성 기능을 사용해서 DDL 만들 때만 사용

 

** 엔티티와 테이블의 차이?

@Entity

- 우선 필수, @Entity만 사용했을 경우 DB와 연결 시 테이블명은 클래스명과 동일하게 설정

  => @Entity 어노테이션을 사용한 상태에서 클래스명이 CrudEntity일 경우 DB에서 CrudEntity 테이블로 연결!

- @Entity(name = "엔티티명")으로 테이블명을 지정해 줄 경우 이후 EntityManager 등을 이용해 쿼리를 사용하는 경우 createQuery("select .. from 엔티티명") 이렇게 사용 가능

 

@Table

- 외부에서 호출하는 용도가 아닌 실제 DB에 붙을 테이블명 어노테이션

- @Entity

@Table(name = "테이블명")

이렇게 지정을 해 놓을 경우 createQuery(select m from 엔티티클래스명) 으로 호출을 해 주면

호출은 엔티티클래스명으로 하지만 실제 DB에는 테이블명의 테이블로 붙게 된다!

 

3. 엔티티 매핑

 

객체와 테이블 매핑 : @Entity, @Table
기본 키 매핑 : @Id
필드와 컬럼 매핑 : @Column
연관관계 매핑 : @ManyToOne, @JoinColumn

 

@Entity
// name과 age Column에 unique 제약조건 추가
@Table(name="MEMBER", uniqueConstraints = {@UniqueConstraint(
		name = "NAME_AGE_UNIQUE",        
        columnNames = {"NAME", "AGE"} )})
public class Member {     

	// 기본키 매핑    
    @Id    
    @Column(name = "ID")    
    private String id;     
    
    // not null, varchar(10)    
    @Column(name = "NAME", nullable = false, length = 10)    
    private String username;     
    
    private Integer age;     
    
    // Java의 enum 사용    
    @Enumerated(EnumType.STRING)    
    private RoleType roleType;     
    
    // Java의 날짜 타입    
    @Temporal(TemporalType.TIMESTAMP)    
    private Date createdDate;     
    
    @Temporal(TemporalType.TIMESTAMP)    
    private Date lastModifiedDate;     
    
    // CLOB, BLOC 타입 매핑    
    @Lob    
    private String description;     
    
    @Transient    
    private String temp;      
    
    //Getter, Setter
} 

public enum RoleType {
	ADMIN, USER
}

 

4. 데이터베이스 스키마 자동 생성

- JPA는 데이터베이스 스키마를 자동으로 생성하는 기능 지원

- 클래스의 매핑 정보와 데이터베이스 방언을 사용하여 데이터베이스 스키마 생성 

애플리케이션 실행 시점에 데이터베이스 테이블을 자동으로 생성

 

hibernate.hbm2ddl.auto 속성

create : 기존 테이블을 삭제하고 새로 생성(DROP + CREATE)

create-drop : CREATE 속성에 추가로 애플리케이션을 종료할 때 생성한 DDL을 제거  (DROP + CREATE + DROP)

update : DB 테이블과 엔티티 매핑 정보를 비교해서 변경 사항만 수정

validate : DB 테이블과 엔티티 매핑정보를 비교해서 차이가 있으면 경고를 남기고 애플리케이션을 실행하지 않음.

DDL을 수행하지 않음

none : 자동 생성 기능을 사용하지 않음

 

주의사항

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

- 초기화 상태로 자동화된 테스트를 진행하는 개발자 환경과 CI서버는 create 또는 create-drop

- 테스트 서버는 update 또는 validate

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

 

5. 기본 키 매핑

- 영속성 컨텍스트는 엔티티를 식별자 값으로 구분하므로 엔티티를 영속 상태로 만들기 위해 식별자 값 반드시 필요

 

@GeneratedValue

- 기본 키 생성 전략

  * 직접 할당: 기본 키를 애플리케이션에 직접 할당

  => em.persist()를 호출하기 전 애플리케이션에서 직접 식별자 값을 할당해야 함. 식별자 값이 없을 경우 예러 발생

  * 자동 생성: 대리 키 사용 방식

     1) IDENTITY: 기본 키 생성을 데이터 베이스에 위임 (= AUTO_INCREMENT)

     2) SEQUENCE : 데이터베이스 시퀀스를 사용해서 기본 키를 할당, 데이터베이스 시퀀스에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장함. 유일한 값을 순서대로 생성 (오라클, PostgreSQL, DB2, H2)
    3) TABLE : 키 생성 테이블을 사용키 생성 전용 테이블 하나를 만들고 여기에 이름과 값으로 사용할 컬럼을 만들어

데이터베이스 시퀀스를 흉내내는 전략. 테이블을 사용하므로 모든 데이터베이스에 적용 가능

    4) AUTO : 선택한 데이터베이스 방언에 따라 방식을 자동으로 선택(Default)

  Ex) 오라클 DB 선택 시 SEQUENCE, MySQL DB 선택 시 IDENTITY 사용

 

@Column

- 객체 필드를 테이블 컬럼에 매핑

- 속성 중 name, nullable이 주로 사용되고 나머지는 잘 사용되지 않음

    1) name : 필드와 매핑할 테이블 컬럼 이름 (default. 객체의 필드 이름)

    2) nullable (DDL) : null 값의 허용 여부 설정, false 설정 시 not null (default. true)   @Column 사용 시 nullable = false 로 설정하는 것이 안전

    3) unique (DDL) : @Table 의 uniqueConstraints와 같지만 한 컬럼에 간단히 유니크 제약조건을 적용

    4) columnDefinition (DDL) : 데이터베이스 컬럼 정보를 직접 줄 수 있음, default 값 설정   (default. 필드의 자바 타입과 방언 정보를 사용해 적절한 컬럼 타입을 생성)

    5) length (DDL) : 문자 길이 제약조건, String 타입에만 사용 (default. 255)

    6) percision, scale (DDL) : BigDecimal, BigInteger 타입에서 사용. 아주 큰 숫자나 정밀한 소수를 다룰 때만 사용(default. precision = 19, scale = 2)

 

@Enumerated

 - 자바의 enum 타입을 매핑할 때 사용

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

                 EnumType.STRING : enum 이름을 데이터베이스에 저장 (default.EnumType.ORDINAL)

 

@Temporal

 - 날짜 타입(java.util.Date, java.util.Calendar)을 매핑할 때 사용

   * value : TemporalType.DATE : 날짜, 데이터베이스 data 타입과 매핑 (2020-12-18) 

                  TemporalType.TIME : 시간, 데이터베이스 time 타입과 매핑 (23:36:33)

                  TemporalType.TIMESTAMP : 날짜와 시간, 데이터베이스 timestamp 타입과 매핑 (2020-12-18 23:36:33)

                   (default. TemporalType은 필수로 지정)

 

@Temporal 을 생략하면 자바의 Date와 가장 유사한 timestamp로 정의

 

@Lob

 - 데이터베이스 BLOB, CLOB 타입과 매핑

  * 지정 속성이 없음. 대신 매핑하는 필드 타입이 문자면 CLOB, 나머지는 BLOB로 매핑

 

@Transient

 - 이 필드는 매핑하지 않음. 데이터베이스에 저장하지 않고 조회하지도 않음.

 객체에 임시로 어떤 값을 보관하고 싶을 때 사용

 

@Access

 - JPA가 엔티티 데이터에 접근하는 방식 지정

  * 필드 접근 : AccessType.FIELD로 지정, 필드에 직접 접근 (private도 접근 가능)

  * 프로퍼티 접근 : AccessType.PROPERTY로 지정 (접근자 Getter 사용)

 

 

5. 엔티티 설계시 주의점

- 엔티티에는 가급적 Setter 사용 X (Setter가 모두 열려있다 == 변경 포인트가 너무 많아서 유지 보수 어렵다)

 

- 모든 연관 관계는 지연로딩으로 설정! (개중요!!!!!!!! 실제 프로젝트 쓸 때 오류 해결할 때 유용)

  * 즉시로딩(EAGER = 멤버를 조회할 때 연관된 Order 조회를 다 하는 것)는 예측 어렵고 어떤 SQL이 실행될지 추적하기 어렵

  * 실무에서 모든 연관관계는 지연로딩(LAZY)로 설정

  * 문맥상에서 원하는 것만 선택해 가져올 수 있음

  * 연관된 엔티티를 함께 DB에서 조회해야 하면 fetch, join 또는 엔티티 그래프 기능을 사용한다

  * @XToOne 관계는 기본이 즉시로딩이므로 직접 지연로딩으로 설정해야 함

 

- 컬렉션은 필드에서 초기화하자

  * 컬렉션은 필드에서 초기화하는 것이 안전

  * null 문제에서 안전


- 테이블, 컬럼명 생성 전략  (SpringPhysicalNamingStrategy)

  * 스프링부트 신규 설정 (엔티티(필드) -> 테이블(컬럼))

    > 카멜 케이스 => 언더스코어 (memberPoint -> member_point)

    > .(점) => _(언더스코어)

    > 대문자 => 소문자

  * 논리명? => 명시적으로 컬럼, 테이블명을 직접 적지 않으면 ImplicitNamingStrategy 사용

  * 물리명? => 모든 논리명에 적용됨, 실제 테이블에 적용

 

+ Recent posts