概要
先日ちょっとした事件に出くわしたので備忘録として記載します。
お仕事でMySQLのライブラリバージョン「MySQL Connector/J 8.0」以上にした際、担当していたアプリが軒並み動かなくなる事象がありました。
その原因と修正の話
調査
調査を行っていたところログに「java.lang.IllegalArgumentException: HOUR_OF_DAY: 0 ->1」の見慣れない文字が・・・
調査の過程で下記ブログに行き当たりました。
ブログにも記載がありますが、日本でも過去にサマータイムが導入されていた時期ある様子
西暦 | 和暦 |
---|---|
1948-05-02 | 昭和23-05-02 |
1949-04-03 | 昭和24-04-03 |
1950-05-07 | 昭和25-05-07 |
1951-05-06 | 昭和26-05-06 |
つまり時刻を含まない形(年月日)だけ受け取れれば問題なしと思っていたのですが、使っていたJavaのライブラリがseasar2だったこともあり、さらに問題が・・・
seasar2ではなぜかDATE型をTimestampに置き換えるようにしている様子・・・
case Types.DATE:
return Timestamp.class;
当然Timestampにしてたら上記のタイムゾーン問題に抵触する訳ですよ。
対応
上記のブログにあったようにタイムゾーンの設定やらなんやらしてみたけどうまくいかず。
困っていたのですが極力修正しないために(バグ生みたくないから・・・)
SQL側を文字列に、受け取り側をStringにする強行手段で解決することに成功
簡易的ではあるけど以下のように
--h.dateには2024-12-27が格納されている場合
select date_format(h.date, '%Y-%m-%d') from hoge h;
と実行するとレスポンスとして2024-12-27
が文字列として返ってくる。
これをJava側でバインド(String型で)して受けとり、後続の処理で時間として使っているのであればcastするなりなんなりすればよいということ。
本来だったらタイムゾーンの設定とかで何とか出来たら影響は少なかったのかもしれないけど、その辺はうまくいかなかったので力業で解決しましたって話。
あとがき
あとはseasar2のBeanMapを使っていたのも問題の原因だったとも思う
DBから受けっとったレスポンスを良しなにMap<String,Object>
にしてくれる機能でseasar2側がTimestampに置き換えていなければDate型でうまくいったのかなとか・・・
思うことは沢山あるけど、この問題は力業でも対応できるって事を共有したかった感じでした。
ベストな方法ではないけど、最小にするならって感じ
とはいえSQL側でStringに変換するので結局BeanMapのままでもいいんだけど
今回は複合的な要因があってこの問題が一般的ではないとは思うけど、この先似たような事象に出くわした誰かのためになったらいいなと思います。
では!