MySQL 데이터베이스 (8.X) 기준 포스팅입니다.
@Enumerated(EnumType.STRING) 매핑 방식
enum을 사용할 때 데이터베이스 저장이 필요한 경우 대부분 @Enumerated(EnumType.STRING) 으로 매핑한다. EnumType.ORDINAL을 쓰면 enum의 순서(int)가 저장됨에 따른 중간삽입, 순서변경 등에 의해 잘못된 값 삽입 문제가 발생할 수 있기 때문에 저장공간을 더 차지하더라도 STRING 을 사용하게 된다.
기존 5.X 버전까지는 @Enumerated(EnumType.STRING) 으로 매핑할 경우 VARCHAR 자료형으로 저장되었지만,
Hibernate 6.2 부터는 ENUM 데이터타입 매핑이 기본값으로 변경되었다.
아래처럼 @Enumerated(EnumType.STRING) 으로 매핑하면 VARCHAR(255)가 아닌 ENUM 타입으로 저장된다.
VARCHAR 로 저장하기
MYSQL ENUM 타입을 그대로 활용하게되면 필드가 추가되었을 때, DDL을 체크하지 않는다면 런타임 오류가 발생할 가능성이 있다. 일반적으로 ddl-auto 는 none 또는 validate 로 설정한다. 이 경우 아래처럼 NEW_STATUS 를 추가하고 실행하면
public enum StoreStatus {
ACTIVE,
INACTIVE,
// 추가
NEW_STATUS
}
문제없이 실행된다. ddl-auto validate 으로는 schema mapping 이 아니기 때문에 enum 변경을 감지할 수 없다. 여기서 변경감지 등에 의한 업데이트문이 나가게되면 NEW_STATUS 는 enum 정의에 없는 값이므로 아래와같이 Data truncated가 발생한다.
결국 SQLException (JPA 기준 DataIntegrityViolationException 으로 wrapping) 으로 이어진다.
컬럼타입으로 ENUM 타입을 사용한다는 의미는, 값이 변경될때마다 DDL로 애플리케이션 코드에 맞춰서 변경해야 한다는 의미와 동일한데 대규모 데이터를 가진 테이블이라면 운영중에 DDL로 업데이트하는 것이 부담스러울 수 있다. 결국 ENUM타입을 쓴다는 의미는 변경되지 않는 고정된 값이라고 믿고 사용하는 케이스가 많을 텐데, 실제로 개발하다보면 고정된 값이라 생각했던 것들도 필드가 추가되는 경우가 꽤 있다.
따라서, ENUM 은 확장성이 제한되므로 VARCHAR 로 처음부터 설계하거나, 아예 별도 테이블로 분리해서 FK 참조를 하는 방식을 이용하는게 더 나을 것 같다. VARCHAR 로 저장하려면 아래처럼 columnDefinition 을 활용하는 방법이 제일 나아보인다.
@Enumerated(EnumType.STRING)
@Column(nullable = false, columnDefinition = "VARCHAR(255)")
private WorkCondition workCondition;
@JdbcTypeCode(SqlTypes.VARCHAR) 를 사용하는 방법도 존재하는 것 같지만 check 제약조건이 걸린 상태로 생성되기때문에 결국 DB 레벨에서 ALTER 로 수정해야한다.
많은 자료들에서 예전 방식인 VARCHAR(255) 방식으로 매핑되는 것으로 다루고 있어서, 초기에 ddl-auto 를 create 또는 update 를 사용했고, 이후 자동 생성된 컬럼을 확인해보지 않았다면, 한번쯤은 확인해보면 좋을 것 같다. 기본적으로 ENUM 데이터타입으로 자동 생성되면 VARCHAR 과 데이터타입이 다르기때문에 호환되지 않으므로 ddl-auto 가 validate 일 경우 SchemaManagementException 발생으로 확인이 가능하다. none 일 경우는 콘솔에서 직접 확인해야 한다.
'JPA' 카테고리의 다른 글
[JPA] @Embeddable 에서 모든 필드가 null 일 경우 NullPointerException 발생 케이스와 해결 방안 (0) | 2025.04.26 |
---|---|
[JPA] EntityManager 정리 (0) | 2024.09.01 |