본문 바로가기
Spring/관련 지식

JPA에서 Enum 활용 방법 (ORDINAL vs STRING 등)

by 정구정구 2026. 7. 21.

이전에 다뤘던 Enum의 객체지향적 활용방법

https://record47584.tistory.com/81

 

Enum의 객체 지향적 활용 방법

Enum 이란?서로 관련된 상수들의 집합을 타입으로 정의한 것단순 static final 상수보다 타입 안정성이 높음 (컴파일 타임에 오타나 잘못된 값을 방지)작성 예시public enum ProductStatus{ FOR_SALE, // 판매 중

record47584.tistory.com

 

 

Enum을 DB 컬럼에 매핑하는 이유

  • 문자열로 상태를 관리하는 경우, 오타나 정합성 문제가 발생할 수 있음
  • 타입 안정성 확보

 

 

@Enumerate 전략 선택 - ORDINAL vs STRING

JPA에서 Enum 필드를 DB 컬럼에 매핑할 때는 @Enumerated 어노테이션을 붙여야 한다. @Enumerated에는 enum 값을 DB에 저장하는 두 가지 전략이 있는데, EnumType 옵션을 통해, 인덱스로 저장(ORDINAL)될지, 문자로 저장(STRING)될지 결정할 수 있다.

 

예시 enum

public enum OrderStatus {
    PENDING, 
    SHIPPED,
    DELIVERED,
    CANCELLED
}

 

ORDINAL

    // 주문 상태
    @Enumerated(EnumType.ORDINAL)
    @Column(nullable = false, length = 20)
    private OrderStatus status;

 

위와 같이 enum을 DB에 @Enumerated(EnumType.ORDINAL)로 저장을 하면, PENDING = 0, SHIPPED = 1, DELIVERED = 2, CANCELLED = 3 으로 DB에 저장된다.

 

 이 전략은 2가지 문제가 있어서 사실상 업무에서 사용하지 않는다. 

  • MySql의 enum 인덱스는 1부터 시작을 하지만, Java의 enum 인덱스는 0부터 시작한다. 그렇기 때문에 매핑한 값이 어긋나면서 엉뚱한 상태 값이 저장되거나 조회되는 문제가 발생할 수 있다.
  • enum 중간에 값이 추가되거나 순서가 바뀌면 저장된 데이터의 의미가 통째로 바뀐다. 

 

STRING (권장)

    // 주문 상태
    @Enumerated(EnumType.STRING)
    @Column(nullable = false, length = 20)
    private OrderStatus status;

 

위와 같은 이유로, 실무에서는 기본적으로 STRING이 전략이 사용된다. 값을 String으로 저장하기 때문에 매핑이 어긋하는 이슈로부터 자유롭다.

 

 

DB 컬럼 타입은? ENUM vs VARCHAR

ENUM

MySQL은 자체적으로 ENUM 타입을 지원한다. 장점이 분명히 있지만 단점이 커서 대부분 쓰이지 않는다.

status ENUM('PENDING', 'SHIPPED', 'DELIVERED') NOT NULL

 

장점

  • 저장 공간이 효율적 (내부적으로 정수로 저장)
  • DB 레벨에서 잘못된 값이 들어오는 것을 막을 수 있음

단점

  • enum을 추가하기 위해서 DB 스카마를 변경해야 함
  • MySSQL의 enum 인덱싱 이슈, 스키마 동화 이슈 발생 가능

 

VARCHAR (권장)

status VARCHAR(20) NOT NULL

 

위와 같이, MySQL에서 지원하는 enum 타입을 쓰지 않고 그냥 문자로 저장하는 방법이다. 실무에서는 이 방법을 쓰는게 권장된다.

 

장점

  • enum 값이 추가/삭제되도 DB를 건드릴 필요가 없음 
  • MySSQL의 enum 인덱싱 이슈, 스키마 동화 이슈에서 자유로움
  • 다른 DB로 옮기더라도 호환성이 좋음 (enum 타입을 지원하지 않는 DB로도 이동 가능)

단점

  • JPA를 거치지 않고 직접 DB에 쓰면 잘못된 데이터가 들어갈 수 있음
  • enum의 이름이 VARCHAR 제한 값을 넘어가면 에러 발생

 

 

@JsonCreator로 Enum 받아오기

@JsonCreator란?

 Json 데이터를 역직렬화할 때 사용되는 어노테이션. 주로 생성자나 정적 팩토리 메서드에서 사용된다.

 

Enum에서 사용하기

public enum ReviewStatus {
    VISIBLE, HIDDEN, DELETED;

    @JsonCreator
    public static ReviewStatus from(String value) {
        try {
            return ReviewStatus.valueOf(value.toUpperCase());
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("유효하지 않은 리뷰 상태입니다: " + value);
        }
    }
}

 

위와 같이 @JsonCreator 어노테이션을 붙인 from을 만들면, 

public class ReviewUpdateRequest {
    private ReviewStatus status; // JSON: {"status": "HIDDEN"}
    // Jackson이 자동으로 ReviewStatus.from("HIDDEN") 호출
}

 

request DTO에 등록된 enum을 자동으로 변환해서 등록해준다.

 

// 상품 등록
@Transactional
public CreateProductResponse create (CreateProductRequest request, LoginAdmin sessionAdmin) {

    // String -> Enum 변환 코드 (이제 필요 없다!)
    ProductStatus status =
            ProductStatus.from(request.getStatus()); 

    if (request.getStock() == 0 && status == ProductStatus.FOR_SALE) {
        throw new CustomException(ErrorCode.INVALID_PRODUCT_STATUS_ZERO_STOCK);
    }

    Product product = request.toEntity(status);

    productRepository.save(product);

    return CreateProductResponse.from(product);
}

 

위처럼 Service 단계에서 enum 변환 코드를 넣을 필요가 없어진다!