[java 자료구조] Oracle + Mybatis 환경에서의 Date 다루기

  • Oracle, Java 8, mybatis3 환경
  • Date컬럼에 데이터가 있는데 이를 select query로 조회하여 Model에 바인딩 시키고자 함.
  • 쿼리에 아무 기능을 추가하지 않고 Date 형태로 Model에 바인딩을 하면 시분초가 없어진 2017-01-01 00:00:00 형태로 남게됨
  • 그래서 아래처럼 쿼리 작성할 때마다 TO_CHAR를 사용해서 포맷에 맞추어 형변환을 시키고 Date 또는 String으로 Model에 바인딩 하곤 했음.
 
SELECT
TO_CHAR(reg_ymdt, 'YYYY-MM-DD HH24:MI:SS') AS registDate
FROM
...
  • 이렇게 하다보니 query 만들때마다 형변환하는 쿼리를 만들어줘야하고, 자칫 포맷형식을 다르게 적으면 엉뚱한 결과를 초래하거나, Date형을 그대로 받아 사용해야하는 상황에서는 다시 형변환하는 과정(String to Date)을 해줘야만 함. .. 귀차니즘의 시작 : 삽질
  • mybatis에서는 자동적으로 org.apache.ibatis.type.SqlDateTypeHandler를 호출하게됨 mybatis 3 문서 참고
  • 해당 핸들러의 내부 데이터 변환 코드는 다음과 같음
 
@Override
public Date getNullableResult(ResultSet rs, String columnName)  throws SQLException {
	return rs.getDate(columnName);
}
  • java.sql.ResultSet.getDate()메소드를 호출하면 실제 ‘yyyy-mm-dd’ 만 가져와 리턴하게됨 (여기서 디버깅 해보면 rs.getTimestamp(columnName)값은 시분초까지 다 들어가 있음)
  • 따라서 시간값이 없는 yyyy-mm-dd 형태로 리턴이 됨
  • mybatis에서는 자동적으로 org.apache.ibatis.type.DateOnlyTypeHandler를 호출하게됨 mybatis 3 문서 참고
  • 해당 핸들러의 내부 데이터 변환 코드는 다음과 같음
 
@Override
public Date getNullableResult(ResultSet rs, String columnName)  throws SQLException {
	java.sql.Date sqlDate = rs.getDate(columnName);
	if (sqlDate != null) {
		return new java.util.Date(sqlDate.getTime());
	}
	return null;
}
  • 위의 org.apache.ibatis.type.SqlDateTypeHandler 변환코드에서 발생한 문제점과 같이 yyyy-mm-dd 만 가져와서 java.sql.Date 객체를 만들고, 이 정보를 토대로 java.util.Date 객체를 만들게 되는데 앞서 시간값을 뺀 정보로 만들어졌기 때문에 결국 동일하게 yyyy-mm-dd 형태로 리턴이 됨
  • 오라클 + mybatis 환경에서 Date타입을 다루기 위해서는 타입핸들러를 명시적으로 만들어줘야 한다는걸 알게됨.
  • 아래처럼 코드를 작성하여 커스텀 핸들러를 만들어 등록을 시켜준다.
  • mybatis-config.xml
 
<typeHandlers>
	<typeHandler handler="com.naver.dbill.admin.common.handler.CustomDateHandler"/>
</typeHandlers>
  • CustomDateHandler.java
 
...
import java.sql.Date;
...
public class CustomDateHandler extends BaseTypeHandler<Date> {
	...
	@Override
	public Date getNullableResult(ResultSet rs, String columnName) throws SQLException {
		Timestamp sqlTimestamp = rs.getTimestamp(columnName);
		if (sqlTimestamp != null) {
			return new Date(sqlTimestamp.getTime());
		}
		return null;
	}
	...
}
  • 위 코드를 작성하고 실행해보면 정상적으로 시분초 값이 있는 완전한 Date 형태를 볼수 있다.
  • 아래처럼 코드를 작성하여 커스텀 핸들러를 만들어 등록을 시켜준다.
  • 단, mybatis 3 문서를 보면 java.sql.Date 와는 다르게 기본으로 설정된 typeHandler가 JDBC에 따라 3가지가 있다.
  • 따라서 작성한 커스텀 핸들러를 적용하기 위해서는 명시적으로 자바타입 과 JDBC타입 을 적어줘야 정상적으로 오버라이딩이 되어 해당 핸들러를 사용하게 된다.
  • mybatis-config.xml
 
<typeHandlers>
		<typeHandler handler="com.naver.dbill.admin.common.handler.CustomDateHandler" javaType="java.util.Date" jdbcType="DATE"/>
</typeHandlers>
  • CustomDateHandler.java 는 위와 동일하다. ( import java.util.Date; 사용으로 변경 )
  • java.sql.Date 는 java.util.Date 을 상속받았다.
 
public class Date extends java.util.Date {
}
  • 검색을 하다보면 알수있겠지만 java.sql.Date 는 JDBC등을 이용해서 데이터베이스의 데이터를 사용하는데 적합하고, java.util.Date 은 보다 범용적인 날짜나 시각정보를 다룰때 적합하다고 한다.
  • toString 메소드의 리턴 Format 형태
    • java.sql.Date : yyyy-mm-dd
    • java.util.Date : EEE MMM dd HH:mm:ss zzz yyyy
  • mybatis 에서 형변환은 mybatis 3 문서에 나와있는 자바타입과 JDBC타입이 일치할 경우에 해당 타입 핸들러를 기본으로 사용하게 된다.
  • Oracle의 JDBC 드라이버가 예상 밖으로 동작하네요. Oracle의 DATE 타입도 문서를 보니 시분초까지 저장하게 되어 있는데, Oracle JDBC 구현체가 DATE 타입의 철학을 오해한게 아닌가하는 생각도 듭니다.
  • 참고로 java.sql.Date, java.sql.TimeStamp는 잘못된 설계라는 비판이 많습니다.
  • 저도 Java의 날짜와 시간 API 라는 글에서 아래와 같이 적은 적이 있습니다.

java.sql.Date 클래스는 상위 클래스인 java.util.Date 클래스와 이름이 같다. 이 클래스를 두고 Java 플랫폼 설계자는 클래스 이름을 지으면서 깜빡 존 듯하다는 조롱까지 나왔다.[24]

그리고 이 클래스는 Comparable 인터페이스에 대한 정의를 클래스 선언에서 하지 않았기 때문에 Comparable과 관련된 Generics 선언을 복잡하게 만들었다.[25]

 

java.sql.TimeStamp 클래스는 java.util.Date 클래스에 나노초(nanosecond) 필드를 더한 클래스이다. 이 클래스는 equals() 선언의 대칭성을 어겼다. Date 타입과 TimeStamp 타입을 섞어 쓰면 a.equals(b)가 true라도 b.equals(a)는 false인 경우가 생길 수 있다.[26]

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

  • 이런 이유 때문에 저는 가급적 Java8에 나온 ZonedDateTime 류를 모델객체에서는 쓰고 있기는합니다. 하지만 그 클래스도 JDBC 레벨에서 제대로 매핑을 안 해주는 경우가 있어서 converter, typeHandler류를 따로 만들어야합니다. 참고로 Spring JDBC에서는 아래와 같이 Converter를 만들어서 해결했습니다.
 
public class ZonedDateTimeConverter implements Converter<Timestamp, ZonedDateTime> {
  @Override
  public ZonedDateTime convert(Timestamp source) {
      return ZonedDateTime.ofInstant(source.toInstant(), ZoneId.of("UTC"));
  }
}
  • java.sql.Date vs java.util.Date 둘 중에 선택한다면 모델 객체에서는 java.util.Date가 더 어울린다는 생각이 듭니다. 모델에 java.sql.Date가 있는 것은 Controller에서 SqlException이 있는 것 같은 비슷한 느낌이랄까요..^^;
  • 삽질을 하더라도 가급적이면 영양가 있는 삽질이 되야 할것같다. (하루종일 이것 붙잡다가 업무를 못해버리는;;)
  • API문서, 블로그문서, 검색결과에 맹신하지말고 실제 소스까지 들어가봐서 확신을 갖자.

 

[출처] https://taetaetae.github.io/2017/03/23/oracle-mybatis-date/

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
161 [Java 자료구조] JPA와 Spring Data JPA의 차이 file 졸리운_곰 2022.09.09 30
160 [java 자료구조] 하이버네이트 쉽게 입문하기 (기초)-환경설정,입력조회 개발 file 졸리운_곰 2022.09.09 22
159 [Java 자료구조] JPA, Hibernate, 그리고 Spring Data JPA의 차이점 졸리운_곰 2022.09.09 23
158 [Java][MyBatisc] myBatis에서 null과 nullString을 체크할 때 졸리운_곰 2021.09.13 33
157 [MongoDB/Java] MongoDB에 JSON 형식 데이터 삽입하기 file 졸리운_곰 2021.07.13 27
156 [Java, MongoDB] mongodb java driver 3.0: how to store JSON document 졸리운_곰 2021.07.13 30
155 [Java 자료구조] [Java] 문자열의 첫 글자 제거 졸리운_곰 2021.05.24 406
154 [Java 자료구조] [java] 특정 문자열 사이의 문자열 추출하기, 정규식 졸리운_곰 2021.05.24 1875
153 [Java 자료구조] [JAVA] Java언어로 JSON 생성, 파싱 예제 file 졸리운_곰 2021.05.17 19
152 [Java 자료구조] [Java] Immutable Class (불변 클래스) file 졸리운_곰 2021.03.07 26
151 [Java 자료구조] 불변 객체란? Java Immutable Object file 졸리운_곰 2021.03.07 48
150 [Java 자료구조] [Java] Immutable Object(불변객체) 졸리운_곰 2021.03.07 44
» [java 자료구조] Oracle + Mybatis 환경에서의 Date 다루기 졸리운_곰 2021.02.25 57
148 Java JSON library Jackson Date Date Json 시리얼라이즈/디씨리얼라이즈 file 졸리운_곰 2021.02.25 28
147 [Java, JSON, jackson] Ignoring new fields on JSON objects using Jackson 졸리운_곰 2021.02.19 16
146 [Java] [Jackson] JsonInclude 속성에 대해 알아보자. 졸리운_곰 2021.02.03 592
145 [java] [jackson] Map - JSON간 변환 졸리운_곰 2021.02.02 41
144 [java] [자료구조] Remove null values from json using jackson 졸리운_곰 2021.02.02 78
143 자바 인코딩 관련 문제 종합 정리 file 졸리운_곰 2021.01.29 40
142 [Java 디자인패턴] [JAVA 디자인 패턴] static을 응용한 싱글톤 패턴(Singleton Pattern) 구현 졸리운_곰 2021.01.22 20
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED