매번 mysql만 사용하고, oracle 쿼리를 만들어 본 적 없었는데, 약간은 뜬금없는 오류에 대해서 겪은 내용 공유합니다.
아래와 같은 쿼리가 있습니다. baseDate는 String값이고 예를 들면, 20140810 과 같은 값을 가지고 있습니다. 특정 날짜 이후의 데이터에 대해서 조회하는 로직입니다.
1 2 3 4 5 6 7 8 9 |
<select id="selectId" resultType="string"> SELECT DISTINCT(id) FROM test WHERE id = #{id} AND time <![CDATA[>]]> to_date(#{baseDate}) </select> |
개발DB에서 성공적으로 동작하여, release했습니다. 그런데 운영DB에서는 해당 로직이 오류가 발생합니다.
1 |
java.sql.SQLException: ORA-01861: literal does not match format string |
찾아보니 Type에 DATE형에 String을 넣으면 발생하는 오류라고 합니다.
(완전 동일한 문제에 대해서 고민하는 블로그가 있네요 http://egloos.zum.com/cspark/v/709399)
결국은 아래처럼 to_date할 때, format을 정의해주었습니다. (여기에서는 YYYYMMDD)
1 2 3 4 5 6 7 8 9 |
<select id="selectId" resultType="string"> SELECT DISTINCT(id) FROM test WHERE id = #{id} AND firstopentime <![CDATA[>]]> to_date(#{baseDate}, 'YYYYMMDD') </select> |
왜 개발DB에서는 되는데, 운영DB에서 안되는지까지 확인되지는 않았지만, 위 오류내용으로는 원인 찾기가 좀 힘들었던 점이 있어서 공유합니다(웃음)
추가로 하나더 팁.
경력직들은 많이 알고 있을 법한데,쿼리를 mybatis에서 작성할 때 변수를 넣는 방법으로 #{value}를 사용합니다. #{value}의 경우에는 결국 매핑할 때, “value”가 됩니다.
1 2 |
SELECT * FROM test WHERE id = #{id} -> SELECT * FROM test WHERE id = "123" |
${value}의 경우에는 매핑할 때, 그대로 써줍니다. 즉, value가 됩니다.
1 2 |
SELECT * FROM test WHERE id = ${id} -> SELECT * FROM test WHERE id = 123 |
보통 ${value}의 경우에는 테이블명을 동적으로 바꾸거나 할 때 이외에는 사용한 경우가 거의 없었습니다. 그런데, oracle에서 id를 이용해서 쿼리하려고 했을 때 #{id}가 되면 “id”로 변환된 후, 실제 DB에서 다시 auto-casting으로 id로 바꾸면서 성능 저하가 발생한다고 하네요. 그래서 그대로 id를 사용하기 위해서 ${id}를 이용하였습니다. 물론 해당 값이 null이 되면 #{id}에 비해서 더 큰 오류가 발생할테니, 주의할 필요는 있을 것 같습니다.