概要
QueryDSL を使用してクエリを構築していますが、先日 IntelliJ IDEA 上に表示されたコンソールをみてびっくりしたので備忘録です。
なんと、LocalDate 型 のプロパティについては、UTC+9 にてパラメーターがバインドされているのです。
通常の、Spring Data JPA にて生成されたクエリについては、特段問題なくパラメーターがバインドされているようでした。
- コンソール上の SQL
select
o.id,
o.order_id
o.purchase_date
from customer_order o
where o.purchase_date = '11/01/2020 09:00:00.000'
and o.order_id = 1
動作について
上記は (おそらく SpyLogger が) コンソール上で表示している値が UTC+9 で表示されているだけのようでした。
tail にて mysql 上のログを監視した結果、日付がバインドされていない動作になっておりました。
- MySQL 上で記録されたログ
select
o.id,
o.order_id,
o.purchase_date
from customer_order o
where o.purchase_date = '2020-11-01'
and o.order_id = 1
補足
上記のコンソール上の SQL において、パラメーターは MM/dd/yyyy HH:00:00.000 の形式にて出力されています。(11/01/2020 09:00:00.000)
Spring Data JPA にて生成されるクエリの場合においても、コンソール上に出力される日付の形式は、上記の形式で yyyy-MM-dd HH:00:00 にて出力されませんでした。
なお、QueryDSL については、Spring Data JPA とは異なる JSR310 のパーサーを独自で実装していますので、パラメータには時刻秒が付加されていないようでした。
package com.querydsl.sql.types;
public class JSR310LocalDateType extends AbstractJSR310DateTimeType<LocalDate> {
public JSR310LocalDateType() {
super(Types.DATE);
}
public JSR310LocalDateType(int type) {
super(type);
}
@Override
public void setValue(PreparedStatement st, int startIndex, LocalDate value) throws SQLException {
Instant i = value.atStartOfDay(ZoneOffset.UTC).toInstant();
st.setDate(startIndex, new Date(i.toEpochMilli()), utc());
}
}
上記の実装になっているので、utc() メソッドと使用している JDBC のドライバ (PreparedStatement の実装) の相性が悪いのか、
と思いとても焦りました。
また、Spring Data JPA がクエリを構築する場合、規定のパーサでは、LocalDate 型についても、'2018-05-01 00:00:00' と、LocalDateTime の形式でパラメーターがバインドされて SQL が実行されました。
- Spring Data JPA にてクエリが構築されて実行される SQL
select
o.id,
o.order_id
o.purchase_date
from customer_order o
where o.purchase_date = '2020-11-01 00:00:00'
and o.order_id = 1