4.1 歴史への探訪
Java オブジェクトをデータベースに保存するタスクは、Java 言語の作成直後に関連していました。当時、Java 言語には Date というデータ型が 1 つだけあり、UNIX 時間標準 (1970 年以降のミリ秒数) に従って時間を格納していました。
当時のデータベースにはすでに日付のさまざまなデータ型があり、少なくとも日付、時刻、および日付 + 時刻には個別の型がありました。
- 日にち
- 時間
- タイムスタンプ
したがって、Java 言語の作成者は、次のクラスを含む特別なパッケージ java.sql を Java 言語に追加しました。
- java.sql.date
- java.sql.Time
- java.sql.タイムスタンプ
これらのクラスのマッピングは本当に楽しいものです。
@Entity
public class TemporalValues {
@Basic
private java.sql.Date sqlDate;
@Basic
private java.sql.Time sqlTime;
@Basic
private java.sql.Timestamp sqlTimestamp;
}
しかし、プログラマは class を使用して作業していたため、Hibernate はDate 型のマッピングを制御するために java.util.Date
特別なアノテーションを追加しました。@Temporal
例:
// If the annotation is missing, then the database will have a TIMESTAMP type
Date dateAsTimestamp;
@Temporal(TemporalType.DATE) // will be mapped to DATE type
Date dateAsDate;
@Temporal(TemporalType.TIME) // will be mapped to TIME type
Date dateAsTime;
タイプjava.util.Calendar
とjava.util.Date
デフォルトのタイプは、データベース内でそれらを表すためにTIMESTAMPタイプを使用します。
4.2 新しい時間
現在、マッピングを使用すると、すべてがはるかにシンプルかつ優れています。すべてのデータベースは、時間を扱うために 4 種類のデータをサポートしています。
- DATE - 日付: 年、月、日。
- TIME - 時間: 時、分、秒。
- TIMESTAMP - 日付、時刻、ナノ秒。
- TIMESTAMP WITH TIME ZONE - TIMESTAMP とタイムゾーン (ゾーン名またはオフセット)。
種類を表すには 日にちjava.time.LocalDate
Java では、 JDK 8 DateTime API のクラスを使用する必要があります。
タイプ時間データベースからの は、Java からの 2 つのタイプ、java.time.LocalTime
およびで表すことができますjava.time.OffsetTime
。何も複雑なことはありません。
そして、型によって表される正確な日付と時刻タイムスタンプ基本的には、Java では 4 つのタイプで表すことができます。
- java.time.Instant
- java.time.LocalDateTime
- java.time.OffsetDateTime
- java.time.ZonedDateTime
そして最後にタイムゾーン付きのタイムスタンプは次の 2 つのタイプで表すことができます。
- java.time.OffsetDateTime
- java.time.ZonedDateTime
DateTime APIについてはすでによく知っているので、この点を覚えるのは難しくありません :)
それらをマッピングすることは純粋に楽しいです:
@Basic
private java.time.LocalDate localDate;
@Basic
private java.time.LocalTime localTime;
@Basic
private java.time.OffsetTime offsetTime;
@Basic
private java.time.Instant instant;
@Basic
private java.time.LocalDateTime localDateTime;
@Basic
private java.time.OffsetDateTime offsetDateTime;
@Basic
private java.time.ZonedDateTime zonedDateTime;
注釈は@Basic
、フィールドが自動的に処理される必要があることを意味します。Hibernate は、このフィールドをマップする必要がある列とタイプを決定します。
4.3 タイムゾーンの操作
タイムゾーンが日付の一部である場合、通常の日付と同様に、タイムゾーンをデータベースに簡単に保存できます。
@Basic
private java.time.OffsetDateTime offsetDateTime;
@Basic
private java.time.ZonedDateTime zonedDateTime;
ただし、タイムゾーンを日付とは別に保存したい場合は、次のようにします。
@Basic
private java.time.TimeZone timeZone;
@Basic
private java.time.ZoneOffset zonedOffset;
その後、Hibernate はデフォルトで VARCHAR 型でそれらを保存します。通常、TimeZone には「UTC + 3」や「Cairo」などの文字列名が付いているため、これは論理的です。
4.4 独自のタイムゾーンの設定
データベースに日付を保存する作業をしていると、現在のタイム ゾーンを設定できる場所がすでに 4 つあることに気づくでしょう。
- サーバーのオペレーティング システム。
- DBMS;
- Javaアプリケーション
- 冬眠します。
DBMS がタイム ゾーン (TimeZone) を指定しない場合は、オペレーティング システムの設定からタイム ゾーンが取得されます。バックアップ DBMS は独自のタイム ゾーンを持つ他のデータ センターに配置されることが多いため、これは不便な場合があります。
したがって、ほとんどすべての DBMS 管理者は、あるサーバーから別のサーバーにデータを簡単に転送できるように単一のゾーンを設定します。
Java アプリケーションでも状況は似ています。異なるデータセンターの異なるサーバー上で実行することもできるため、通常は明示的なタイムゾーンがあります。
java -Duser.timezone=UTC ...
または、プログラムの実行中に次のようにします。
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
そしてもちろん、Hibernate ではタイムゾーンを明示的に設定できます。
まず、SessionFactory を構成するときに指定できます。
settings.put(
AvailableSettings.JDBC_TIME_ZONE,
TimeZone.getTimeZone("UTC")
);
第二に、タイムゾーンを指定できます特定のセッションの場合:
Session session = sessionFactory()
.withOptions()
.jdbcTimeZone(TimeZone.getTimeZone("UTC"))
.openSession();
4.5 @TimeZoneStorage アノテーション
プログラマーが 1 つの国 (および 1 つのタイム ゾーン) での作業に基づいてデータベースの設計を開始し、数年後に別のタイム ゾーンでの作業のサポートを追加する必要が生じたということがよくあります。
したがって、タイムゾーンを保存するためにデータベースに別の列を追加しただけです。これは非常に一般的な状況であるため、Hibernate は特定の日付のタイムゾーンを別の列に保存できる特別なアノテーションを追加しました。
例:
@TimeZoneStorage(TimeZoneStorageType.COLUMN)
@TimeZoneColumn(name = "birthday_offset_offset")
@Column(name = "birthday_offset")
private OffsetDateTime offsetDateTimeColumn;
@TimeZoneStorage(TimeZoneStorageType.COLUMN)
@TimeZoneColumn(name = "birthday_zoned_offset")
@Column(name = "birthday_zoned")
private ZonedDateTime zonedDateTimeColumn;
これは松葉杖です。しかし、これには言い訳もあります。DateTime API がまだ存在していなかった時代に登場したからです。また、TimeZone をクラスに保存することは不可能でしたjava.util.Date
。
コード内でこのようなことが頻繁に起こらないことを願っています。