4.1 Excursus ke dalam sejarah

Tugas menyimpan objek Java ke database relevan segera setelah pembuatan bahasa Java. Saat itu, hanya ada satu tipe data dalam bahasa Java, Date, yang menyimpan waktu menurut standar waktu UNIX: sebagai jumlah milidetik sejak 1970.

Nah, di database saat itu sudah ada tipe data yang berbeda untuk tanggal, setidaknya ada tipe terpisah untuk tanggal, waktu dan tanggal + waktu:

  • TANGGAL
  • WAKTU
  • URUTAN WAKTU

Oleh karena itu, pembuat bahasa Java menambahkan paket khusus ke dalamnya - java.sql, yang berisi kelas:

  • java.sql.tanggal
  • java.sql.Waktu
  • java.sql.timestamp

Memetakan kelas-kelas ini sangat menyenangkan:


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

Tetapi karena pemrogram biasa bekerja dengan kelas java.util.Date, Hibernate menambahkan anotasi khusus @Temporaluntuk mengontrol pemetaan tipe Tanggal.

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;

Tipe java.util.Calendardan java.util.Datetipe default menggunakan tipe TIMESTAMP untuk mewakilinya dalam database.

4.2 Waktu baru

Saat ini, dengan pemetaan, semuanya jauh lebih sederhana dan lebih baik. Semua database mendukung 4 jenis data untuk bekerja dengan waktu:

  • TANGGAL - tanggal: tahun, bulan dan hari.
  • WAKTU - waktu: jam, menit, detik.
  • TIMESTAMP - tanggal, waktu, dan nanodetik.
  • TIMESTAMP WITH TIME ZONE - TIMESTAMP dan zona waktu (nama zona atau offset).

Untuk mewakili jenis TANGGALdi Jawa, Anda perlu menggunakan kelas java.time.LocalDatedari JDK 8 DateTime API.

JenisWAKTUdari database dapat diwakili oleh dua jenis dari Java: java.time.LocalTimedan java.time.OffsetTime. Tidak ada yang rumit.

Dan tanggal dan waktu yang tepat diwakili oleh jenisnyaURUTAN WAKTUdi pangkalan, di Jawa dapat diwakili oleh 4 jenis:

  • java.time.Instan
  • java.time.LocalDateTime
  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Dan akhirnyaURUTAN WAKTU DENGAN ZONA WAKTUdapat diwakili oleh dua jenis:

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

Karena Anda sudah familiar dengan DateTime API , mengingat hal ini tidak akan menyulitkan Anda :)

Memetakan mereka adalah kesenangan 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 @Basicberarti bidang tersebut harus diproses secara otomatis : Hibernasi akan memutuskan kolom dan jenis bidang mana yang harus dipetakan.

4.3 Bekerja dengan zona waktu

Jika zona waktu adalah bagian dari tanggal, maka menyimpannya dalam database itu sederhana - seperti tanggal biasa:

@Basic
private java.time.OffsetDateTime offsetDateTime;

@Basic
private java.time.ZonedDateTime zonedDateTime;

Namun, jika Anda ingin menyimpan zona waktu secara terpisah dari tanggal:

@Basic
private java.time.TimeZone timeZone;

@Basic
private java.time.ZoneOffset zonedOffset;

Kemudian Hibernate akan menyimpannya dalam tipe VARCHAR secara default. Yang sebenarnya logis, karena TimeZone biasanya memiliki nama string seperti "UTC + 3" atau "Cairo".

4.4 Mengatur zona waktu Anda sendiri

Saat Anda bekerja dengan menyimpan tanggal ke database, Anda akan menemukan fakta bahwa sudah ada 4 tempat di mana Anda dapat mengatur zona waktu saat ini:

  • sistem operasi server;
  • DBMS;
  • aplikasi jawa
  • Hibernasi.

Jika DBMS tidak menentukan zona waktu (TimeZone), maka DBMS akan mengambilnya dari pengaturan sistem operasi. Ini bisa merepotkan, karena DBMS cadangan sering kali terletak di pusat data lain yang memiliki zona waktunya sendiri.

Oleh karena itu, hampir semua admin DBMS menetapkan satu zona agar data dapat dengan mudah dipindahkan dari satu server ke server lainnya.

Situasinya mirip dengan aplikasi Java. Itu juga dapat dijalankan di server yang berbeda di pusat data yang berbeda, sehingga biasanya memiliki zona waktu yang jelas.


java -Duser.timezone=UTC ...

Atau saat program sedang berjalan:

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

Dan, tentu saja, Hibernate memungkinkan Anda mengatur zona waktu secara eksplisit.

Pertama, dapat ditentukan saat mengonfigurasi SessionFactory:

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

Kedua, zona waktu dapat ditentukanuntuk sesi tertentu:

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

4.5 anotasi @TimeZoneStorage

Sering terjadi bahwa pemrogram mulai merancang basis data berdasarkan bekerja di satu negara (dan satu zona waktu), dan kemudian setelah beberapa tahun mereka perlu menambahkan dukungan untuk bekerja di zona waktu yang berbeda.

Oleh karena itu, mereka hanya menambahkan kolom terpisah ke database untuk menyimpan zona waktu. Ini adalah situasi yang umum sehingga Hibernate telah menambahkan anotasi khusus yang memungkinkan Anda menyimpan TimeZone dari tanggal tertentu di kolom terpisah.

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 kruk. Tapi ada juga alasan untuk itu: itu muncul pada saat API DateTime belum ada. Dan tidak mungkin menyimpan TimeZone di kelas java.util.Date.

Saya sangat berharap Anda tidak akan sering melihat ini di kode Anda.