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

Hibernate –日付と時刻のマッピング

1. 前書き

この記事では、java.sqljava.utiljava.timeパッケージのクラスを含め、Hibernateで時間列の値をマッピングする方法を示します。

2. プロジェクトのセットアップ

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


    org.hibernate
    hibernate-core
    5.2.12.Final


    com.h2database
    h2
    1.4.194

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

3. タイムゾーンの設定

When dealing with dates, it’s a good idea to set a specific time zone for the JDBC driver.このようにして、アプリケーションはシステムの現在のタイムゾーンから独立します。

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

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

別の方法は、セッションファクトリの構築に使用される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タイプ

The type java.util.Date contains both date and time information, up to millisecond precision.ただし、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;

@Temporalアノテーションには、タイプTemporalType.の単一のパラメーター値があります。必要な基になるSQLタイプに応じて、DATETIME、または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"));

これまで見てきたように、the java.util.Date type (milliseconds precision) is not precise enough to handle the Timestamp value (nanoseconds precision).

したがって、データベースからエンティティを取得すると、最初に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タイプのマッピング

Since Java 8, the new Java Date and Time API is available for dealing with temporal values。 このAPIは、java.util.Dateおよびjava.util.Calendarクラスの問題の多くを修正します。

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

  • LocalDateDATEにマップされます

  • LocalTimeOffsetTimeTIMEにマップされます

  • InstantLocalDateTimeOffsetDateTime、および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でさまざまなタイプの一時的な値をマップする方法を示しました。

記事のソースコードはover on GitHubで入手できます。