Hibernate - Pemetaan Tarikh dan Masa

1. Pengenalan

Dalam artikel ini, kami akan menunjukkan cara memetakan nilai lajur temporal di Hibernate, termasuk kelas dari pakej java.sql , java.util dan java.time .

2. Penyediaan Projek

Untuk menunjukkan pemetaan jenis temporal, kita memerlukan pangkalan data H2 dan versi terbaru perpustakaan inti hibernate :

 org.hibernate hibernate-core 5.4.12.Final   com.h2database h2 1.4.194 

Untuk versi perpustakaan inti hibernate terkini , pergi ke repositori Maven Central.

3. Persediaan Zon Waktu

Semasa berurusan dengan tarikh, adalah idea yang baik untuk menetapkan zon waktu tertentu untuk pemacu JDBC. Dengan cara ini aplikasi kita tidak bergantung pada zon waktu sistem semasa.

Sebagai contoh, kami akan menetapkannya setiap sesi:

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

Cara lain adalah dengan menyiapkan harta hibernate.jdbc.time_zone dalam fail sifat Hibernate yang digunakan untuk membina kilang sesi. Dengan cara ini kita dapat menentukan zon waktu sekali untuk keseluruhan aplikasi.

4. Pemetaan Jenis java.sql

The java.sql pakej mengandungi jenis JDBC yang selaras dengan jenis ditakrifkan oleh standard SQL:

  • Tarikh sepadan dengan jenis DATE SQL, yang hanya tarikh tanpa masa
  • Waktu sepadan dengan jenis TIME SQL, yang merupakan waktu dalam sehari yang ditentukan dalam jam, minit dan saat
  • Cap waktu merangkumi maklumat mengenai tarikh dan waktu dengan ketepatan hingga nanodetik dan sepadan dengan jenis TIMESTAMP SQL

Oleh kerana jenis ini sesuai dengan SQL, maka pemetaannya relatif lurus ke depan. Kita boleh menggunakan anotasi @Basic atau @Column :

@Entity public class TemporalValues { @Basic private java.sql.Date sqlDate; @Basic private java.sql.Time sqlTime; @Basic private java.sql.Timestamp sqlTimestamp; }

Kami kemudian dapat menetapkan nilai yang sesuai seperti ini:

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

Perhatikan bahawa memilih jenis java.sql untuk bidang entiti mungkin tidak selalu menjadi pilihan yang baik. Kelas-kelas ini khusus untuk JDBC dan mengandungi banyak fungsi yang tidak digunakan lagi.

5. Pemetaan Jenis java.util.Date

Jenis java.util.Date mengandungi maklumat tarikh dan masa, hingga ketepatan milisaat. Tetapi ia tidak berkaitan langsung dengan jenis SQL mana pun.

Inilah sebabnya mengapa kita memerlukan penjelasan lain untuk menentukan jenis SQL yang diinginkan:

@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 anotasi mempunyai nilai parameter tunggal jenis TemporalType. Ini boleh menjadi DATE , TIME atau TIMESTAMP , bergantung pada jenis SQL yang mendasari yang ingin kita gunakan untuk pemetaan.

Kami kemudian dapat menetapkan bidang yang sesuai seperti ini:

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

Seperti yang kita lihat, yang java.util.Date jenis (milisaat ketepatan) tidak cukup tepat untuk mengendalikan nilai Cap Masa (nanosaat ketepatan).

Oleh itu, apabila kita mengambil entiti dari pangkalan data, kita tidak akan menemui contoh cap java.sql.Timestamp dalam bidang ini, walaupun pada mulanya kita meneruskan java.util. Tarikh :

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

Ini mesti baik untuk kod kami kerana Cap Waktu memanjangkan Tarikh .

6. Pemetaan java.util.Calendar Jenis

Seperti java.util.Date , jenis kalendar java.util. mungkin dipetakan ke jenis SQL yang berbeza, jadi kita harus menentukannya dengan @Temporal .

Satu-satunya perbezaan ialah Hibernate tidak menyokong pemetaan Kalendar hingga MASA :

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

Inilah cara kita dapat menetapkan nilai medan:

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. Pemetaan Jenis java.time

Sejak Java 8, Java Date and Time API baru tersedia untuk menangani nilai-nilai temporal . API ini menyelesaikan banyak masalah kelas java.util.Date dan java.util.Calendar .

Jenis dari pakej java.time dipetakan secara langsung ke jenis SQL yang sesuai. Oleh itu, anda tidak perlu menyatakan penjelasan @Temporal secara eksplisit :

  • LocalDate dipetakan hingga DATE
  • LocalTime dan OffsetTime dipetakan menjadi TIME
  • Instant , LocalDateTime , OffsetDateTime dan ZonedDateTime dipetakan ke TIMESTAMP

Ini bermaksud bahawa kita boleh menandai bidang ini hanya dengan anotasi @Basic (atau @Column ), seperti ini:

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

Setiap kelas temporal dalam pakej java.time mempunyai kaedah parse statik () untuk mengurai nilai String yang disediakan menggunakan format yang sesuai. Jadi inilah cara kita dapat menetapkan nilai bidang entiti:

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. Kesimpulannya

Dalam artikel ini, kami telah menunjukkan cara memetakan nilai temporal dari pelbagai jenis di Hibernate.

Kod sumber untuk artikel tersebut terdapat di GitHub.