자바의 열거형 타입은 엔티티의 분류 코드나 상태 값을 저장하기에 적합한 타입입니다.
Boolean
이나, Int
타입으로 저장해도 사용상에 문제는 없지만 열거형을 사용하게 되면 사람이 이해하기 쉽습니다.
// 결제 정보
@Entity
class Payment : AbstractEntity() {
...
// 결제 상태를 정의합니다.
@Enumerated(EnumType.STRING)
@Column(name = "paymentType", length = 64, nullable = false)
var type: PaymentType? = null
}
// 결제 상태
enum class PaymentType(
private val messageCode: String,
) {
INITIALIZED("enum.payment.type.initialized"), // 주문서 작성 완료
PENDING("enum.payment.type.pending"), // 결제 대기
SUCCESS("enum.payment.type.success"), // 결제 성공
FAILURE("enum.payment.type.failure"), // 결제 실패
CANCELLED("enum.payment.type.cancelled"), // 결제 취소
REJECTED("enum.payment.type.rejected"), // 결제 반려됨
EXPIRED("enum.payment.type.expired"), // 결제 시간 만료됨
;
}
편의상 열거형 타입의 데이터를 데이터베이스에 저장하기 위해서 @Enumerated
애노테이션으로 이름을 문자열로 저장할 지(EnumType.STRING
), 열거형의 순서로 저장할 지(EnumType.ORDINAL
) 지정하여 관리합니다만,
이는 몇 가지 문제점을 가집니다.
특히, 이름이 변경되는 경우가 잦은데 개발/배포 DB가 별도로 운용되고 브랜치가 다수 운용되는 경우 DB에서 값을 불러올 때 열거형 타입의 데이터를 변환하는 데 실패하여 시스템 장애로 이어집니다.
따라서 불편함은 있지만 @javax.persistence.Convert
애노테이션을 사용하여 컨버터를 직접 지정하여 열거형 타입의 데이터를 직접 변환하는 것이 장애 발생을 최소화할 수 있습니다.
가령
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
enum class PaymentType {
INITIALIZED("enum.payment.type.initialized"),
...
;
@JvmStatic
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
fun parse(name: String?): PaymentType? =
name?.let { EnumUtils.getEnumIgnoreCase(PaymentType::class.java, it.trim()) }
// 해당 열거형 타입의 컨버터 클래스를 내부에 정의합니다.
class Converter : AttributeConverter<PaymentType, String> {
override fun convertToDatabaseColumn(attribute: CmsHistoryType?): String? =
attribute?.name
override fun convertToEntityAttribute(dbData: String?): CmsHistoryType? =
dbData?.let { CmsHistoryType.parse(it) }
}
}
열거형 타입의 클래스 내부에 컨버터를 작성하고, @Enumerated
애노테이션을 @Covert
애노테이션으로 변경합니다.
@Entity
class Payment : AbstractEntity() {
...
@Convert(converter = PaymentType.Converter::class)
@Column(name = "paymentType", length = 64, nullable = false)
var type: PaymentType? = null
}
아쉬운 점은 엔티티에서 열거형 타입을 사용할 때 마다 컨버터를 사용해야 한다는 점입니다.