4.1 Ekskursus ke dalam sejarah

Tugas menyimpan objek Java ke pangkalan data adalah relevan hampir sejurus selepas penciptaan bahasa Java. Pada masa itu, hanya terdapat satu jenis data dalam bahasa Java, Date, yang menyimpan masa mengikut standard UNIX-time: sebagai bilangan milisaat sejak 1970.

Nah, dalam pangkalan data pada masa itu sudah ada jenis data yang berbeza untuk tarikh, sekurang-kurangnya terdapat jenis yang berasingan untuk tarikh, masa dan tarikh + masa:

  • TARIKH
  • MASA
  • STAMP MASA

Oleh itu, pencipta bahasa Java menambahkan pakej khas padanya - java.sql, yang mengandungi kelas:

  • java.sql.date
  • java.sql.Time
  • java.sql.timestamp

Memetakan kelas ini adalah keseronokan sebenar:


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

Tetapi memandangkan pengaturcara digunakan untuk bekerja dengan kelas java.util.Date, Hibernate menambah anotasi khas @Temporaluntuk mengawal pemetaan jenis Tarikh.

Contoh:

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

Jenis java.util.Calendardan java.util.Datejenis lalai menggunakan jenis TIMESTAMP untuk mewakilinya dalam pangkalan data.

4.2 Masa baharu

Pada masa ini, dengan pemetaan, semuanya lebih mudah dan lebih baik. Semua pangkalan data menyokong 4 jenis data untuk berfungsi dengan masa:

  • TARIKH - tarikh: tahun, bulan dan hari.
  • MASA - masa: jam, minit, saat.
  • TIMESTAMP - tarikh, masa dan nanosaat.
  • TIMESTAMP DENGAN ZON MASA - TIMESTAMP dan zon masa (nama zon atau offset).

Untuk mewakili jenis TARIKHdalam Java, anda perlu menggunakan kelas java.time.LocalDatedaripada API DateTime JDK 8.

taipMASAdaripada pangkalan data boleh diwakili oleh dua jenis dari Java: java.time.LocalTimedan java.time.OffsetTime. Tiada yang rumit.

Dan tarikh dan masa yang tepat diwakili oleh jenisSTAMP MASAdi pangkalan, di Jawa ia boleh diwakili oleh 4 jenis:

  • java.time.Instant
  • java.time.LocalDateTime
  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Dan akhirnyaSTAMP MASA DENGAN ZON MASAboleh diwakili oleh dua jenis:

  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Memandangkan anda sudah biasa dengan API DateTime , mengingati perkara ini tidak sukar untuk anda :)

Memetakan mereka adalah keseronokan murni:

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

Anotasi @Basicbermaksud bahawa medan harus diproses secara automatik : Hibernate akan menentukan lajur dan jenis medan ini harus dipetakan.

4.3 Bekerja dengan zon waktu

Jika zon waktu adalah sebahagian daripada tarikh, maka menyimpannya dalam pangkalan data adalah mudah - sama seperti tarikh biasa:

@Basic
private java.time.OffsetDateTime offsetDateTime;

@Basic
private java.time.ZonedDateTime zonedDateTime;

Walau bagaimanapun, jika anda ingin menyimpan zon waktu secara berasingan daripada tarikh:

@Basic
private java.time.TimeZone timeZone;

@Basic
private java.time.ZoneOffset zonedOffset;

Kemudian Hibernate akan menyimpannya dalam jenis VARCHAR secara lalai. Yang, sebenarnya, adalah logik, kerana TimeZone biasanya mempunyai nama rentetan seperti "UTC + 3" atau "Kaherah".

4.4 Menetapkan zon waktu anda sendiri

Apabila anda bekerja dengan menyimpan tarikh ke pangkalan data, anda akan menemui fakta bahawa sudah ada 4 tempat di mana anda boleh menetapkan zon waktu semasa:

  • Sistem pengendalian pelayan;
  • DBMS;
  • Aplikasi Java
  • Hibernate.

Jika DBMS tidak menentukan zon waktu (Zon Waktu), maka ia akan mengambilnya daripada tetapan sistem pengendalian. Ini boleh menyusahkan, kerana DBMS sandaran selalunya terletak di pusat data lain yang mempunyai zon waktu mereka sendiri.

Oleh itu, hampir semua pentadbir DBMS menetapkan zon tunggal supaya data boleh dipindahkan dengan mudah dari satu pelayan ke pelayan yang lain.

Keadaan ini serupa dengan aplikasi Java. Ia juga boleh dijalankan pada pelayan yang berbeza di pusat data yang berbeza, jadi ia biasanya mempunyai zon waktu yang jelas.


java -Duser.timezone=UTC ...

Atau semasa program berjalan:

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

Dan, sudah tentu, Hibernate membolehkan anda menetapkan zon waktu anda secara eksplisit.

Pertama, ia boleh ditentukan semasa mengkonfigurasi SessionFactory:

settings.put(
    AvailableSettings.JDBC_TIME_ZONE,
    TimeZone.getTimeZone("UTC")
);

Kedua, zon waktu boleh ditentukanuntuk sesi tertentu:

Session session = sessionFactory()
    .withOptions()
    .jdbcTimeZone(TimeZone.getTimeZone("UTC"))
    .openSession();

4.5 anotasi @TimeZoneStorage

Selalunya berlaku bahawa pengaturcara mula mereka bentuk pangkalan data berdasarkan bekerja di satu negara (dan satu zon waktu), dan kemudian selepas beberapa tahun mereka perlu menambah sokongan untuk bekerja di zon waktu yang berbeza.

Oleh itu, mereka hanya menambah lajur berasingan ke pangkalan data untuk menyimpan zon waktu. Ini adalah situasi biasa yang Hibernate telah menambah anotasi khas yang membolehkan anda menyimpan TimeZone tarikh tertentu dalam lajur yang berasingan.

Contoh:

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

Ini adalah tongkat. Tetapi terdapat juga alasan untuknya: ia muncul pada masa API DateTime belum wujud. Dan adalah mustahil untuk menyimpan TimeZone dalam kelas java.util.Date.

Saya sangat berharap anda tidak akan sering melihat ini dalam kod anda.