1. 序章

この記事では、 java .sql java .util javaのクラスを含む、Hibernateの時間列値をマップする方法を示します。 ].timeパッケージ。

2. プロジェクトの設定

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

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

hibernate-core ライブラリの現在のバージョンについては、 MavenCentralリポジトリにアクセスしてください。

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 には、最大ナノ秒の精度で日付と時刻に関する情報が含まれ、 TIMESTAMPSQLタイプに対応します。

これらのタイプは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タイプ

タイプjava.util.Dateには、最大ミリ秒の精度で日付と時刻の両方の情報が含まれます。ただし、SQLタイプとは直接関係ありません。

これが、目的の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;

The @Temporal アノテーションには、タイプの単一のパラメーター値があります TemporalType。 どちらでもかまいません日にち 時間またタイムスタンプ 、マッピングに使用する基になるSQLタイプによって異なります。

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

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"));

TimestampDateを拡張するため、これはコードにとっては問題ないはずです。

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 andTimeAPIが使用可能になりました。 このAPIは、java.util.Dateおよびjava.util.Calendarクラスの問題の多くを修正します。

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

  • LocalDateDATEにマップされます
  • LocalTimeおよびOffsetTimeTIMEにマップされます
  • Instant LocalDateTime ResetDateTime 、およびZonedDateTimeTIMESTAMPにマップされます

これは、次のように、 @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でさまざまなタイプの時間値をマップする方法を示しました。

この記事のソースコードは、GitHubから入手できます。