기존 프로젝트에 기능 추가를 하는 중, 개발 환경에서 db 스키마 변경이 필요했다. 문제는 스키마 변경 후 데이터베이스 정합성, 도메인 무결성 등을 위배하는 데이터들 때문에 기존에 정상적으로 작동하던 API 중 몇몇 API에서 오류가 났다. 그중에 한 API 오류 해결 사례를 정리하는 포스팅.
에러 발생
{
"code": 400,
"message": "Bad Request / Could not extract column [3] from JDBC ResultSet [MONTH] [n/a] / org.hibernate.exception.GenericJDBCException: Could not extract column [3] from JDBC ResultSet [MONTH] [n/a] / class org.springframework.orm.jpa.JpaSystemException",
"timestamp": "2025-02-18T11:29:36.532228600",
"path": "/v1/user",
"method": "GET"
}
유저 목록을 반환하는 API 호출 시 400 에러가 발생했다. 에러 메시지 등으로 파악한 원인은 birthdate 필드의 일부 값이 2000-00-00, 0000-00-00과 같은 잘못된 형식으로 저장되어 있었는데 이 값이 LocalDate 타입으로 변환하려 할 때 오류가 발생하는 것이었다. LocalDate는 YYYY-MM-DD 형식이어야 하며, Month나 Day에 00이 포함된 날짜는 유효하지 않은 값으로 처리된다.
data class UserModel(
val id: Long,
val email: String,
val birthDate: LocalDate?,
)
조회에 사용되는 data 클래스는 위와 같다.
Projections.constructor(
UserModel::class.java,
cgsUserEntity.id,
cgsUserEntity.email,
cgsUserEntity.birthdate,
)
querydsl로 작성된 select 절의 파라미터는 위와 같다.
해결 방법
- AttributeConverter를 추가하여 해결하였다.
@Converter(autoApply = false)
class LocalDateConverter : AttributeConverter<LocalDate?, String?> {
override fun convertToDatabaseColumn(attribute: LocalDate?): String? {
return attribute?.toString()
}
override fun convertToEntityAttribute(dbData: String?): LocalDate? {
return if (dbData == "0000-00-00" || dbData == "2000-00-00") {
null
} else {
dbData?.let { LocalDate.parse(it) }
}
}
}
- 2000-00-00, 0000-00-00과 같은 잘못된 날짜 값을 처리하는 로직을 추가하여, 해당 값을 null로 변환하였다. 프로젝트에서 birthDate를 null 허용 가능 타입을 사용하고 있었으므로 유효하지 않은 값을 그냥 null로 변환하기로 하였다.
- 엔티티에는 다음과 같이 생성한 컨버터를 명시해 주었다.
@NotNull
@Convert(converter = LocalDateConverter::class) // db 0000-00-00 값 등 대응 위해 설정
@Column(name = "birthdate", nullable = false)
var birthdate: LocalDate? = null
적용 후 API 정상 작동됨을 확인하였다.
내 생각
개발 환경에서도 데이터베이스 정합성과 도메인 무결성은 반드시 지켜야 한다. 아무리 개발 환경에서 사용하는 db라고 무지성으로 부적합한 데이터를 넣는 것은 지양해야 한다. 잘못된 데이터가 들어가면 시스템이 정상적으로 작동하지 않거나, 비즈니스 로직을 깨뜨릴 수 있다. 위 내용은 사실 유효한 데이터만 데이터베이스에 저장되어 있었다면, 굳이 하지 않아도 될 대응이었다.
'Spring' 카테고리의 다른 글
비밀번호 없이 회원가입, 로그인 구현 (kotlin + spring boot) (0) | 2025.02.08 |
---|---|
클린 스프링: 스프링 개발자를 위한 클린 코드 전략 - 이일민(토비) (28) | 2024.11.18 |
스프링부트 코틀린 프로젝트에 jsp 띄우기 (0) | 2024.08.11 |
설정 파일을 통한 환경별 Property 관리 (0) | 2024.07.26 |
BasicErrorController 상속받아 커스텀하기 (0) | 2024.05.01 |