JPA 필드와 컬럼 매핑

2019-10-27

JPA 필드와 컬럼 매핑

1. @Column

@Column은 객체 필드를 테이블 컬럼에 매핑하는 방법입니다.

가장 많이 사용되고 기능도 많지만, 속성중에 name과 nullable이 주로 사용되고, 나머지는 잘 사용하질 않습니다.

속성 기능 기본값
name 필드와 매핑할 테이블의 컬럼이름 객체의 필드 이름
insertable
(거의사용X)
엔티티 저장 시 이 필드도 같이 저장합니다.
false로 설정하면 이 필드는 데이터베이스에 저장하지 않습니다.
false 옵션은 읽기 전용일 때 사용합니다.
true
updateable
(거의사용X)
엔티티 수정 시 이필드도 같이 수정합니다.
false로 설정하면 데이터베이스에 수정하지 않습니다.
false 옵션은 읽기 전용일 때 사용합니다.
true
table
(거의사용X)
하나의 엔티티를 두 개 이상의 테이블에 매핑할 때 사용합니다.
지정한 필드를 다른 테이블에 매핑할 수 있습니다.
현재 클래스가
매핑된 테이블
nullable(DDL) null 값의 허용 여부를 설정합니다. false로 설정하면 not null 제약이 붙습니다. true
unique(DDL) @Table의 uniqueConstraints와 같지만
한 컬럼에만 간단히 유니크 제약조건을 걸 때 사용합니다.
만약 두개 이상의 유니크 제약조건을 걸고 싶으면
@Table의 uniqueConstraints를 사용해야합니다.
 
columnDefinition(DDL) 데이터베이스 컬럼 정보를 직접 줄 수 있습니다. 필드의 자바 타입과
방언 정보를 사용해서
적절한 컬럼 타입을 생성합니다.
lenghth(DDL) 문자 길이 제약조건, String 타입에만 사용합니다. 255
precision, scale(DDL) BigDecimal 타입에서 사용합니다.(BigInteger도 사용가능)
precision은 소수점을 포함한 전체 자릿수를,
scale은 소수의 자릿수 입니다.
참고로 double,float타입에는 적용되지 않습니다.
아주 큰 숫자나 정밀한 소수를 다루어야 할 때만 사용합니다.
precision = 19,
scale=2

1-1 @Column 생략을 하면 어떻게 될까?

int data1; //@Column생략, 기본타입
data1 integer not null // 생성된 DDL 
  
Integer data2; // @Column생략, 객체타입
data2 integer // 생성된 DDL
  
@Column
int data3; //@Column사용, 기본타입
data3 integer// 생성된 DDL

data3의 경우 @Column 어노테이션을 사용했는데, nullable이 true로 설정되기 때문에 안전하지 않을 수 있습니다.

기본타입은 null이라는게 존재하지 않기 때문입니다.

2. @Enumerated

속성 기능 기본값
value - EnumType.ORDINAL : enum 순서를 데이터베이스에 저장
- EnumType.String : enum 이름을 데이터베이스에 저장
EnumType.ORDINAL

2-1. enum 클래스 선언

enum RoleType {
  ADMIN,USER
}

2-1-1. enum 매핑 (EnumType.STRING)

@Enumerated(EnumType.STRING)
private RoleType roleType;
member.setRoleType(RoleType.ADMIN): // DB에 ADMIN으로 저장

2-1-2. enum 매핑 (EnumType.ORDINAL)

@Enumerated(EnumType.ORDINAL) // 기본값
private RoleType roleType;
member.setRoleType(RoleType.ADMIN): // DB에 0으로 저장

2-2. EnumType.STRING

  • 장점 : 저장된 enum의 순서가 바뀌거나 enum이 추가되어도 안전합니다.
  • 단점 : DB에 저장되는 데이터 크기가 ORDINAL에 비해서 큽니다.

2-3. EnumType.ORDINAL

  • 장점 : DB에 저장되는 데이터 크기가 작습니다.
  • 단점 : 이미 저장된 enum의 순서를 변경할 수 없습니다.

ADMIN(0) , USER(1) 에서 ADMIN(0) , NEW(1) USER(2) 로 변경되면 망하게된다..

3. @Temporal

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

속성 기능 기본값
value - TemporalType.DATE : 날짜, 데이터베이스 date 타입과 매핑(예 : 2019 - 09 -09)
- TemporalType.TIME : 시간, 데이터베이스 time 타입과 매핑(예 : 11:11.11)
- TemporalType.TIMESTAMP : 날짜와 시간, 데이터베이스 timestamp 타입과 매핑( 예: 2019 - 09 - 09 10:10:10)
TemporalType은 필수로 지정해야 합니다.
@Temporal(TemporalType.DATE)
private Date date; // 날짜

@Temporal(TemporalType.TIME)
private Date time; // 날짜

@Temporal(TemporalType.TIMESTAMP)
private Date timestamp; // 날짜와 시간

요즘에는 java.util.Date와 java.util.Calendar를 잘 안쓰고 있습니다.

그 대신에 LocalDateTime을 주로 이용하고 있기 때문에 해당 어노테이션은 잘 이용되지 않을 거라 생각됩니다.

아직 java.util.Date를 사용하고 있으면, 사용하지마세요.

저는 @Temporal를 이용하지 않고.

private LocalDate localDate; // MySQL DATE 타입

private LocalDateTime localDateTime; // MySQL DATETIME 타입

이렇게 사용하고 있습니다.

4. @Lob

데이터베이스 BLOB, CLOB 타입과 매핑합니다.

@Lob은 지정할 수 있는 속성이 없습니다. 대신에 매핑하는 필드 타입이 문자면 CLOB으로 매핑하고 나머지는 BLOB로 매핑합니다.

  • CLOB : String, char[], java.sql.CLOB
  • BLOB : byte[], java.sql.BLOB
@Lob
private String lobString; 

@Lob
private byte[] lobByte; 
//오라클
lobString clob,
lobByte blob,

//MySQL
lobString longtext,
lobByte longblob

//PostgreSQL
lobString text,
lobByte oid

5. @Transient

이 필드는 엔티티에 매핑해도 데이터베이스에 저장되지 않습니다.

객체에 임시로 값을 보관하고 싶을 때 사용합니다.

@Transient
private Integer temp;

6. @Access

JPA가 엔티티 데이터에 접근하는 방식을 지정합니다.

  • 필드 접근 : AccessType.FIELD로 지정합니다. 필드에 직접 접근하는 방법입니다. 필드가 private이어도 접근이 가능합니다.
  • 프로퍼티 접근 : AccessType.PROPERTY로 지정합니다. Getter를 사용하는 방법입니다.

@Access를 설정하지 않으면 @Id의 위치를 기준으로 접근 방식이 설정됩니다.

@Id 어노테이션이 필드에 붙어있으면 AccessType.FIELD로 접근 방식이 설정 됩니다.

6-1. 프로퍼티 접근 코드

@Entity
@Access(AccessType.PROPERTY) // @Id 어노테이션때문에 생략 가능.
public class Member {
  
  private String id;
  
  private String data1;
  
  @Id
  public String getId() {
    return id;
  }
  
  @Column
  public String getData1() {
    
  }
}

6-2. 필드, 프로퍼티 접근 함께 사용

@Entity
public class Member {
  @Id
  private String id;
  
  @Transient
  private String firstName;
  
  @Transient
  private String lastName;
  
  @Access(AccessType.PROPERTY)
  public String getFullName() {
    return firstName + lastName;
  }
}

@Id가 필드에 있으므로 기본적으로 필드 접근 방식을 이용하지만, getFullName()만 프로퍼티 방식을 사용합니다.

따라서 엔티티를 저장할 때 FULLNAME 컬럼에 firstName + lastName의 결과가 저장됩니다.