休止状態 - 日付と時刻のマッピング

1前書き

この記事では、 java.sql java.util 、および java.time パッケージのクラスを含め、Hibernateで時系列列の値をマップする方法を説明します。

2プロジェクト設定

時間型のマッピングを説明するために、H2データベースと最新版の hibernate-core ライブラリが必要になります。

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.2.12.Final</version>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.194</version>
</dependency>

現在のバージョンの hibernate-core ライブラリについては、https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.hibernate%22%20AND%20a%3A%にアクセスしてください。 22hibernate-core%22[Maven Central]リポジトリ。

3タイムゾーンの設定

  • 日付を扱うときは、JDBCドライバに特定のタイムゾーンを設定することをお勧めします。

この例では、セッションごとに設定します。

session = HibernateUtil.getSessionFactory().withOptions()
  .jdbcTimeZone(TimeZone.getTimeZone("UTC"))
  .openSession();

もう1つの方法は、セッションファクトリの構築に使用されるHibernateプロパティファイルで hibernate.jdbc.time zone__プロパティを設定することです。これにより、アプリケーション全体に対して1回タイムゾーンを指定できます。

4 java.sql 型のマッピング

java.sql パッケージには、標準SQLで定義されている型と一致するJDBC型が含まれています。

  • Date DATE SQL型に対応します。これは日付のみです。

時間がない ** Time TIME SQL型に対応します。これはその日の時刻です。

時、分、秒で指定 ** Timestamp には、日付と時刻に関する情報が正確に含まれます

ナノ秒までで、 TIMESTAMP SQL型に対応します

これらの型はSQLと一致しているので、それらのマッピングは比較的簡単です。 @ Basic アノテーションまたは @ Column アノテーションを使用できます。

@Entity
public class TemporalValues {

    @Basic
    private java.sql.Date sqlDate;

    @Basic
    private java.sql.Time sqlTime;

    @Basic
    private java.sql.Timestamp sqlTimestamp;

}

その後、対応する値を次のように設定できます。

temporalValues.setSqlDate(java.sql.Date.valueOf("2017-11-15"));
temporalValues.setSqlTime(java.sql.Time.valueOf("15:30:14"));
temporalValues.setSqlTimestamp(
  java.sql.Timestamp.valueOf("2017-11-15 15:30:14.332"));

エンティティフィールドにjava.sql型を選択することが常に良い選択とは限らないことに注意してください。これらのクラスはJDBC固有であり、多くの非推奨機能が含まれています。

5マッピング java.util.Date Type

  • java.util.Date 型には、ミリ秒の精度までの日付と時刻の両方の情報が含まれます。

これが、目的のSQL型を指定するための別の注釈が必要な理由です。

@Basic
@Temporal(TemporalType.DATE)
private java.util.Date utilDate;

@Basic
@Temporal(TemporalType.TIME)
private java.util.Date utilTime;

@Basic
@Temporal(TemporalType.TIMESTAMP)
private java.util.Date utilTimestamp;

@ Temporal アノテーションには TemporalType型の単一パラメータ値があります。マッピングに使用する基礎となるSQL型に応じて、 DATE TIME 、または TIMESTAMP__のいずれかになります。

対応するフィールドを次のように設定します。

temporalValues.setUtilDate(
  new SimpleDateFormat("yyyy-MM-dd").parse("2017-11-15"));
temporalValues.setUtilTime(
  new SimpleDateFormat("HH:mm:ss").parse("15:30:14"));
temporalValues.setUtilTimestamp(
  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
    .parse("2017-11-15 15:30:14.332"));

これまで見てきたように、 java.util.Date タイプ(ミリ秒の精度)は、タイムスタンプ値(ナノ秒の精度)を処理するのに十分なほど正確ではありません。

そのため、データベースからエンティティを取得すると、最初は java.util.Date を永続化していても、当然ながらこのフィールドに java.sql.Timestamp インスタンスが見つかります。

temporalValues = session.get(TemporalValues.class,
  temporalValues.getId());
assertThat(temporalValues.getUtilTimestamp())
  .isEqualTo(java.sql.Timestamp.valueOf("2017-11-15 15:30:14.332"));

Timestamp Date を拡張しているので、これは私たちのコードにとっては問題ないはずです。

6. マッピング java.util.Calendar タイプ

java.util.Date と同様に、 java.util.Calendar タイプは異なるSQLタイプにマップされる可能性があるため、 @ Temporal を使用してそれらを指定する必要があります。

唯一の違いは、Hibernateが Calendar から TIME へのマッピングをサポートしていないことです。

@Basic
@Temporal(TemporalType.DATE)
private java.util.Calendar calendarDate;

@Basic
@Temporal(TemporalType.TIMESTAMP)
private java.util.Calendar calendarTimestamp;

フィールドの値を設定する方法は次のとおりです。

Calendar calendarDate = Calendar.getInstance(
  TimeZone.getTimeZone("UTC"));
calendarDate.set(Calendar.YEAR, 2017);
calendarDate.set(Calendar.MONTH, 10);
calendarDate.set(Calendar.DAY__OF__MONTH, 15);
temporalValues.setCalendarDate(calendarDate);

7. java.time 型のマッピング

  • Java 8以降、新しいJava Date and Time APIが時間値を扱うために利用可能になりました** 。このAPIは、 java.util.Date および java.util.Calendar クラスの多くの問題を解決します。

java.time パッケージの型は、対応するSQL型に直接マッピングされています。そのため、 @ Temporal アノテーションを明示的に指定する必要はありません。

  • LocalDate DATE にマップされます

  • LocalTime OffsetTime TIME にマップされます

  • Instant LocalDateTime OffsetDateTime 、および ZonedDateTime は、

TIMESTAMP にマッピング

これは、次のように、これらのフィールドに @ Basic (または @ Column )アノテーションでのみマークを付けることができることを意味します。

@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;

java.time パッケージ内のすべての一時クラスには、提供された String 値を適切な形式で解析するための静的 parse() メソッドがあります。それで、エンティティフィールドの値を設定する方法は次のとおりです。

temporalValues.setLocalDate(LocalDate.parse("2017-11-15"));

temporalValues.setLocalTime(LocalTime.parse("15:30:18"));
temporalValues.setOffsetTime(OffsetTime.parse("08:22:12+01:00"));

temporalValues.setInstant(Instant.parse("2017-11-15T08:22:12Z"));
temporalValues.setLocalDateTime(
  LocalDateTime.parse("2017-11-15T08:22:12"));
temporalValues.setOffsetDateTime(
  OffsetDateTime.parse("2017-11-15T08:22:12+01:00"));
temporalValues.setZonedDateTime(
  ZonedDateTime.parse("2017-11-15T08:22:12+01:00[Europe/Paris]"));

8結論

この記事では、Hibernateでさまざまなタイプの時間値をマッピングする方法を説明しました。

この記事のソースコードはhttps://github.com/eugenp/tutorials/tree/master/persistence-modules/hibernate5[GitHubで利用可能]です。