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.Calendarjava.util.Dateデフォルトのタイプは、データベース内でそれらを表すためにTIMESTAMPタイプを使用します。

4.2 新しい時間

現在、マッピングを使用すると、すべてがはるかにシンプルかつ優れています。すべてのデータベースは、時間を扱うために 4 種類のデータをサポートしています。

  • DATE - 日付: 年、月、日。
  • TIME - 時間: 時、分、秒。
  • TIMESTAMP - 日付、時刻、ナノ秒。
  • TIMESTAMP WITH TIME ZONE - TIMESTAMP とタイムゾーン (ゾーン名またはオフセット)。

種類を表すには 日にちjava.time.LocalDateJava では、 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

コード内でこのようなことが頻繁に起こらないことを願っています。