티스토리 뷰
코프링으로 개발하면서 zeroDateTime(0000-00-00 00:00:00)인 LocalDateTime 값 관련해서 마주한 내용을 포스팅해봤습니다.
배경
as-is(파이썬) 코드로 되어 있는 배치 스크립트를 코틀린으로 이전하는 작업에서 발생했습니다.
as-is 코드에서 사용하지 않는 row는 수정 시간을 zeroDateTime으로 변경해주는 로직이 있었습니다.
SQL문으로 직접 수정해주었기 때문에 별 문제 없는 로직이었습니다.
허나, 스프링 환경에서 적용하려고 하니 다음과 같은 문제가 발생했습니다.
바로 LocalDate 타입에서 month와 day 값의 최소값이 1인 점이었습니다.
import java.time.LocalDate
import java.time.LocalDateTime
fun main() {
val localDate = LocalDate.of(0, 0, 0)
}
위 코드를 테스트해보아도 다음과 같은 에러가 발생하여 zeroDateTime을 사용하기 어려웠습니다.
해결 방법
[1]. zeroDateTime 사용하지 않기
해결 방법이 사용하지 않기라서 의아하실 수도 있습니다.
하지만 zeroDateTime을 사용하는 건 결코 좋은 방법은 아닙니다.
다양한 이유가 있겠지만, LocalDate에서도 0달 0일을 제공하지 않는 걸로 이유를 들 수 있겠습니다.
spring.datasource.url에서도 zeroDateTIme을 null로 변경해주는 옵션이 있습니다.
url: jdbc:mysql://localhost:3306/cafe?characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
이 옵션이 있으면 데이터베이스에 zeroDateTime으로 저장되어있더라도 null로 가져옵니다.
저도 다행히 제가 작업하는 테이블을 사용하는 팀은 한 곳 밖에 없었고, 로직을 수정해주셔서 zeroDateTime을 걷어낼 수 있었습니다.
[2]. jdbcTemplate.batchUpdate
jdbcTemplate.batchUpdate를 사용하면 zeroDateTime을 넣을 수 있습니다.
PreparedStatement에서 파라미터를 넣을 수 있는데, timestamps 대신 string을 넣을 수 있습니다.
"0000-00-00 00:00:00"문자열을 넣어서 데이터베이스에 zeroDateTime을 넣을 수 있습니다.
아래 예시 코드 살펴보시면 됩니다.
package com.laboratorykkoon9.kotlinspring.cafe.service
import com.laboratorykkoon9.kotlinspring.cafe.repository.CafeRepository
import com.laboratorykkoon9.kotlinspring.cafe.service.model.CreateCafeDto
import com.laboratorykkoon9.kotlinspring.cafe.service.model.UpdateCafeDto
import mu.KotlinLogging
import org.springframework.data.domain.Pageable
import org.springframework.jdbc.core.BatchPreparedStatementSetter
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.sql.PreparedStatement
@Service
class CafeService(
private val jdbcTemplate: JdbcTemplate
) {
val logger = KotlinLogging.logger {}
private fun batchUpdate(list: List<Long>) {
try {
jdbcTemplate.batchUpdate("""
update menus
set modified_at=?
where id=?
""",
object : BatchPreparedStatementSetter {
override fun setValues(ps: PreparedStatement, i: Int) {
ps.setString(1, "0000-00-00 00:00:00")
ps.setLong(2, list[i])
}
override fun getBatchSize(): Int {
return list.size
}
}
)
} catch (e: Exception) {
logger.error("fail batch update", e)
}
}
}
결론
위에서 언급했듯이 zeroDateTime을 사용하기 보다는 다른 방법으로 처리하는걸 고민해보시길 바랍니다.
무조건 사용해야 한다면 convertToNull 옵션과 함께 create 혹은 update를 사용할 때에는 jdbcTemplate.batchUpdate를 사용하는 걸 추천드립니다.
'개발 노트' 카테고리의 다른 글
[스프링+코틀린] mock 없이 통합 테스트하기 (0) | 2023.09.21 |
---|---|
[스프링+코틀린] H2 Create Table 및 Insert 에러 (0) | 2023.09.21 |
git push한 commit 취소하기 (0) | 2023.09.01 |
[스프링] yaml 파일 하나로 스프링 환경변수 관리하기 (0) | 2023.09.01 |
[스프링+자바] Failed to deserialize java.time.LocalDateTime (0) | 2023.08.28 |
- Total
- Today
- Yesterday
- Algorithm
- Olympiad
- Spring
- 테라폼
- JPA
- node.js
- programmers
- 백준
- 알고리즘
- C++
- Spring Boot
- 프로그래머스
- BOJ
- BAEKJOON
- 객체지향
- 이팩티브 자바
- Effective Java
- kkoon9
- AWS
- 정규표현식
- 디자인패턴
- 클린 코드
- MSA
- 클린 아키텍처
- Java
- 코테
- kotest
- 디자인 패턴
- 이펙티브 자바
- Kotlin
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |