참새의 이야기
@Enumerated(EnumType.STRING)을 깜빡하면 생기는 일 본문
Enum 타입의 필드는 DB에서 tinyint 혹은 enum이라는 type으로 관리된다.
예를 들어, 아래와 같이 StudyType이라는 enum 값이 있다고 하자.
public enum StudyType {
OFFLINE,
ASSIGNMENT;
}
tinyint의 경우라면 각각에 0, 1이라는 숫자가 붙어 관리된다.
만약 위와 같은 StudyType에 새로운 값이 추가된다면 어떤 일이 일어날까?
OFFLINE에 이어서 기존에는 ASSIGNMENT가 따라왔지만, ONLINE이 사이에 추가되는 경우를 생각해보자.
OFFLINE과 ASSGIGNMENT의 tinyint는 1과 2로 밀리게 된다.
이런 문제는 삭제 시에도 똑같이 발생한다.
enum값과 대응되는 숫자가 바뀔 수 있다는 점이 문제다.
이를 방지하기 위해 enum이라는 type으로 관리할 수 있다.
'OFFLINE', 'ONLINE'라는 값 자체를 database에 저장하는 것이다.
이런 방식을 사용하기 위해 enum으로 관리할 필드에는 @Enumerated(EnumType.STRING)
여기까지는 기본적인 강의나 책에서도 많이 설명해주는 이야기다.
이 글은 본론은 여기부터다.
@Enumerated(EnumType.STRING)
깜빡한 탓에 발생한 두 가지 문제가 발생했다.
[문제 1] Value out of Range
우리 서비스의 production 환경에서는 ddl-auto 설정을 none으로 사용하고 있다.
따라서 테이블이 새로 생긴다면 직접 datagrip을 통해 테이블을 생성하고 있다.
enum 타입의 필드는 @Enumerated(EnumType.STRING)
를 붙여서 관리하고 있기 때문에 tinyint가 아닌 enum이라는 타입으로 생성했다.
sentry를 통해서 예외가 발생하고 있다는 사실을 알게 되어 확인해보니 아래와 같은 예외가 발생하고 있었다.Value 'OFFLINE' is outside of valid range for type java.lang.Byte
@Enumerated(EnumType.STRING)
를 깜빡한 탓에 발생한 예외였다. 데이터베이스에는 enum으로 관리하고, 코드상으로는 숫자로 관리하고 있어서 타입의 불일치가 발생한 것이다.
이를 해결하기 위해 `@Enumerated(EnumType.STRING)`를 붙여줬고, 이후로 production 환경에서는 문제가 발생하지 않았다.
[문제 2] Check constraint violated
이번 문제는 develop 환경에서 발생했다.
develop 환경은 ddl-auto를 update로 설정하여 사용하고 있다.
앞서 @Enumerated(EnumType.STRING)
를 누락한 일로 인해 이미 develop 환경의 데이터베이스에서는 tinyint로 필드가 설정되어 있었고, check constraint까지 설정되어 있었다.@Enumerated(EnumType.STRING)
를 추가하여 다시 개발 서버를 구동한 후에 JPA에 의해 tinyint로 설정되어 있던 필드는 enum 타입의 필드로 잘 수정되었다.
하지만, JPA가 check constraint까지는 제거해주지 않아서 문제가 발생했다.
check constraint는 값을 0, 1, 2로 제한하고 있었고,
api를 통해 들어온 요청은 enum 타입으로 삽입을 시도했기 때문에 타입의 불일치가 다시 한 번 발생한 것이다.
'Spring' 카테고리의 다른 글
Querydsl로 동적 쿼리 활용하기 (4) | 2024.02.14 |
---|---|
Querydsl 기본 세팅 (0) | 2024.02.05 |
[Spring Security] Authentication Architecture (0) | 2023.11.05 |
[Spring Security] Spring security Architecture (0) | 2023.11.05 |
[MVC2] API 예외 처리 (2) | 2023.08.15 |