※JDBC全般の話なのかOracle特有の話なのかは未確認だがAPI仕様を見る限りJDBC全般の話かも。
JavaからJDBCを使用してOracleにSQLを投げるときにSQLのWHERE句に日時が入っているときはタイムゾーンに関して注意が必要。
PreparedStatementにsetTimeStampやsetDateしてSQLを実行する際、JDBCは引数で渡すDateのエポック秒でSQLを実行するのではなく、引数で渡したDataをマシンのデフォルトタイムゾーン
で出力した(タイムゾーンを伴わない)日時でSQLを実行する。DBを受け取った日時をDBのタイムゾーン設定に基づいて解釈する。
なので特に対策をしないで実行すると次のような問題が起こる。
- クライアントマシンのタイムゾーンとDB(Oracle)のタイムゾーンが異なると意図する結果が戻らない。
- クライアントマシンのタイムゾーンが一致していたとしてもJavaで勝手にサマータイムとかが考慮されて一時間ずれた結果が戻ったりする。
特に二つ目の問題は、プログラムをリリースした時期が冬で正常に動作していたのにサマータイムの季節に突然発症したりして厄介。
以上を踏まえるとクライアントのJavaプログラムでSQLを呼び出すときには次の処理を忘れずに行う必要がある。
- Javaプログラム中でDBのタイムゾーンをGMT-HH形式で保持する。
Timezone oracleTZ = TimeZone.getTimeZone("GMT-5");
- そのタイムゾーンをデフォルトタイムゾーンとして指定する。
TimeZone.setDefault(oracleTZ);
デフォルトにすると不都合な場合はPreparedStatementで時刻を扱う都度設定。
PreparedStatement ps = ..... ; ps.setTimestamp( 1, t, Calendar.getInstance(oracleTZ) );
まとめると
- OracleJDBC(OracleのみならずJDBC全般の可能性あり)はタイムゾーン情報を持たないためJavaプログラム中にデータベースのタイムゾーン設定する必要がある。
- Javaプログラムでタイムゾーンを設定する場合は"EST"みたいな三文字略称を使うと勝手にサマータイムとかが考慮されることがあるので"GMT-5"のような形式で設定するのがよい。
捕捉
もっとも大抵の場合はWHERE句でバインド変数の日時を使うのを避けてOracleのSYSDATEなどDB内で完結した表現で日時を設定するのが無難と言えば無難。
0 件のコメント:
コメントを投稿