JPA 엔티티 매핑: 객체와 데이터베이스 테이블의 매핑

엔티티(Entity) 매핑

JPA 엔티티 매핑은 다음과 같은 주요 어노테이션과 개념을 활용하여 이루어집니다.

 

  • 객체와 테이블 매핑: @Entity, @Table
  • 기본 키 매핑: @Id, @GeneratedValue
  • 필드와 컬럼 매핑: @Column
  • 연관 관계 매핑: @JoinColumn, @ManyToOne, @ManyToMany 등
  • 상속 관계 매핑: @Inheritance, @DiscriminatorColumn, @DiscriminatorValue

 

 

@Entity

  • 엔티티 클래스임을 지정하여 JPA에게 알려줍니다.
  • 기본 생성자가 필요합니다.
  • 저장할 필드에 `final`을 사용하면 안 됩니다.
  • final 클래스, enum, interface, inner 클래스에는 사용할 수 없습니다.

@Table

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

 

다른 어노테이션을 설명하기에 앞서 예제 코드부터 하나 보여드리겠습니다.

import jakarta.persistence.*;

@Getter
@Setter
@Entity 
@Table(name="user") 
public class Member { 
	
	@Id 
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id; 
	
	@Column (name = "name", length = 10, unique = true) 
	private String username;
	
	private Integer age; 
    
	@Enumerated(EnumType.STRING)
	private RoleType roleType;
}

public enum RoleType { 
	ADMIN, USER
}

 

 

@Id, @GeneratedValue

@Id:

엔티티 클래스에서 주요 식별자(primary key)를 가리키는 필드를 지정할때 사용됩니다.

 

@GeneratedValue:

주요 식별자(primary key) 필드의 값을 어떻게 생성하지 지정하는데 사용됩니다. 주로 데이터베이스에서 자동으로생성되는 값을 사용하는 경우에 활용됩니다. 데이터베이스마다 기본 키를 생성하는 방식이 서로 다르기 때문에 @GeneratedValue에 옵션을 주어 지정해주면 됩니다. 예를 들어 MySQL은 기본 키를 자동으로 설정해주는 `AUTO_INCREMENT`기능이 있지만, Oracle에서는 시퀀스를 이용하여 값을 생성합니다. 이렇게 서로 다른 방식으로 기본키를 생성하기 때문에 JPA에서는 @GeneratedValue 어노테이션으로 자동 생성 전략을 지정해주어야 합니다.

  • GenerationType.IDENTITY:
    데이터베이스의 AUTO_INCREMENT 기능을 이용하여 값(기본키)을 생성합니다. MySQL, PostgreSQL 등에서 사용됩니다.
  • GenerationType.SEQUENCE:
    데이터베이스의 시퀀스를 사용해서 값(기본키)을 생성합니다. Oracle 등에서 사용됩니다. 
  • GenerationType.TABLE:
    별도의 키 생성 테이블을 사용하여 값을 생성합니다. 시퀀스를 지원하지않는 데이터베이스에서 시퀀스를 흉내내고 싶을 때 사용할 수 있는 전략입니다.  
  • GenerationType.AUTO:
    JPA 구현체가 가장 적절한 생성 전략을 자동으로 선택합니다. 앞서 설명한 3개 중 하나를 선택하고, 특정 데이터베이스에 종속되지 않고 여러 데이터베이스에서 동작하도록 합니다. AUTO를 사용할 때 SEQUENCE나TABLE 전략이 선택되면 시퀀스나 키 생성용 테이블을 미리 만들어 두어야 합니다. 
@Id를 붙이는 타입은 Long을 사용하자!!
 Long을 사용하는 이유는 두 가지가 있습니다. 첫 번째 이유는 Primitive가아닌Wrapper 타입이기 때문입니다. 원시 타입은 기본이 0이기 때문에 값이 0인 경우 값이 없어서 0인 건지, 키 값이 0인 건지 구분하기 어려울 수 있습니다. 두 번째 이유는 데이터 범위가 Integer보다 Long이 크기 때문입니다. 성능 차이도 크게 나지 않기 때문에 Long을 사용하는 것을 권장합니다.


GenerationType.SEQUENCE나 GenerationType.TABLE 전략을 선택하는 경우

@SequenceGenerator 혹은 @TableGenerator 어노테이션에 속성을 설정하여 붙여줘야 합니다. 이에 관한 설명을 건너뛰도록 하겠습니다.  

 

@Column

필드를 컬럼에 매핑합니다.

  • name: 데이터베이스 테이블의 컬럼 이름을 지정합니다. 기본값은 엔티티 필드의 이름과 동일합니다.
  • unique: 컬럼의 값들이 고유(unique)해야 하는지 여부를 지정합니다.
  • nullable: 컬럼의 값이 널(null)을 허용하는지 여부를 지정합니다.
  • length: 문자열 타입 컬럼의 최대 길이를 지정합니다.
  • columnDefinition: 컬럼의 데이터 타입과 추가 설정을 직접 지정합니다.
  • precision와 scale: 십진수 컬럼의 전체 자릿수와 소수 자릿수를 지정합니다.
  • insertable: 이 속성은 엔티티를 삽입할 때 해당 필드의 값을 데이터베이스 컬럼에 포함시킬지 여부를 지정합니다. 기본값은 true입니다. 만약 insertable을 false로 설정하면 해당 필드는 엔티티를 데이터베이스에 삽입할 때 해당 컬럼에 값을 포함시키지 않습니다.
  • updatable: 이 속성은 엔티티를 업데이트할 때 해당 필드의 값을 데이터베이스 컬럼에 업데이트할지 여부를 지정합니다. 기본값은 true입니다. 만약 updatable을 false로 설정하면 해당 필드는 엔티티를 업데이트할 때 해당 컬럼의 값을 변경하지 않습니다.
@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "product_name", unique = true, nullable = false, length = 100, insertable = true, updatable = false)
    private String name;

    @Column(columnDefinition = "TEXT")
    private String description;

    @Column(precision = 10, scale = 2)
    private BigDecimal price;

    // ...
}

 

@Enumerated

Enum 타입을 데이터베이스에 어떻게 매핑할지를 지정하는데 사용됩니다. Enum 타입을 데이터베이스에 저장할 때는 해당 Enum 상수의 이름이나 순서 값을 사용하고, 문자열이나 숫자와 같은 타입으로 저장합니다. 

  • EnumType.STRING:
    enum 상수의 이름을 그대로 데이터베이스에 저장하는 방식입니다. enum 상수의 이름을 데이터베이스 컬럼에 저장하여 데이터베이스에 텍스트로 저장됩니다.
  • EnumType.ORDINAL:
    enum 상수의 순서 값을 데이터베이스에 저장하는 방식입니다. 테이블 컬럼에 저장할 때 정수로 저장됩니다.