4.1 Tarihe yolculuk

Java nesnelerini veritabanına kaydetme görevi, Java dilinin oluşturulmasından hemen sonra ilgiliydi. O zamanlar, Java dilinde UNIX-zaman standardına göre zamanı depolayan tek bir veri türü vardı: 1970'den beri milisaniye sayısı olarak.

Eh, o zamanlar veritabanlarında tarihler için zaten farklı veri türleri vardı, en azından tarih, saat ve tarih + saat için ayrı türler vardı:

  • TARİH
  • ZAMAN
  • ZAMAN BİLGİSİ

Bu nedenle, Java dilinin yaratıcıları ona özel bir paket eklediler - sınıfları içeren java.sql:

  • java.sql.tarihi
  • java.sql.Zaman
  • java.sql.timestamp

Bu sınıfların haritasını çıkarmak gerçek bir zevktir:


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

Ancak programcılar eskiden sınıfla çalıştıkları için Hibernate , Date türünün eşlemesini kontrol etmek için java.util.Dateözel bir ek açıklama ekledi .@Temporal

Örnek:

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

Tür java.util.Calendarve java.util.Datevarsayılan tür, onları veritabanında temsil etmek için TIMESTAMP türünü kullanır.

4.2 Yeni zaman

Şu anda, haritalama ile her şey çok daha basit ve daha iyi. Tüm veritabanları zamanla çalışmak için 4 tür veriyi destekler:

  • TARİH - tarih: yıl, ay ve gün.
  • ZAMAN - zaman: saat, dakika, saniye.
  • TIMESTAMP - tarih, saat ve nanosaniye.
  • ZAMAN DİLİMİ İLE ZAMAN BİLGİSİ - ZAMAN BİLGİSİ ve saat dilimi (bölge adı veya ofset).

Türü temsil etmek TARİHjava.time.LocalDateJava'da, JDK 8 DateTime API'sinden bir sınıf kullanmanız gerekir .

TipZAMANveritabanından Java'dan iki türle temsil edilebilir: java.time.LocalTimeve java.time.OffsetTime. Karmaşık bir şey yok.

Ve türün temsil ettiği kesin tarih ve saatZAMAN BİLGİSİtemelde, Java'da 4 türle temsil edilebilir:

  • Java.time.Anında
  • java.time.LocalDateTime
  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Ve sonundaZAMAN DİLİMİYLE ZAMAN DÜŞÜNCESİiki türle temsil edilebilir:

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

DateTime API'sine zaten aşina olduğunuz için , bu konuyu hatırlamanız sizin için zor olmayacak :)

Onları haritalamak saf bir zevktir:

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

Ek açıklama, alanın otomatik olarak@Basic işlenmesi gerektiği anlamına gelir : Hazırda Bekletme, bu alanın hangi sütun ve türde eşlenmesi gerektiğine karar verir.

4.3 Saat dilimleriyle çalışma

Saat dilimi bir tarihin parçasıysa, bunları veritabanında saklamak basittir - tıpkı normal bir tarih gibi:

@Basic
private java.time.OffsetDateTime offsetDateTime;

@Basic
private java.time.ZonedDateTime zonedDateTime;

Ancak, saat dilimlerini tarihten ayrı olarak saklamak istiyorsanız:

@Basic
private java.time.TimeZone timeZone;

@Basic
private java.time.ZoneOffset zonedOffset;

Sonra Hazırda Bekletme, bunları varsayılan olarak VARCHAR türünde saklar. Aslında mantıklıdır, çünkü TimeZone genellikle "UTC + 3" veya "Kahire" gibi bir dize adına sahiptir.

4.4 Kendi saat diliminizi ayarlama

Tarihleri ​​​​veritabanına kaydetme ile çalışırken, halihazırda geçerli saat dilimini ayarlayabileceğiniz 4 yer olduğu gerçeğiyle karşılaşacaksınız:

  • Sunucu işletim sistemi;
  • VTYS;
  • java uygulaması
  • hazırda bekletme

DBMS bir saat dilimi (Zaman Dilimi) belirtmezse, işletim sistemi ayarlarından alacaktır. Yedek DBMS'ler genellikle kendi saat dilimlerine sahip diğer veri merkezlerinde bulunduğundan, bu sakıncalı olabilir.

Bu nedenle, neredeyse tüm DBMS yöneticileri, verilerin bir sunucudan diğerine kolayca aktarılabilmesi için tek bir bölge ayarlar.

Durum bir Java uygulamasında da benzerdir. Farklı veri merkezlerindeki farklı sunucularda da çalıştırılabilir, bu nedenle genellikle belirli bir saat dilimine sahiptir.


java -Duser.timezone=UTC ...

Veya program çalışırken:

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

Ve tabii ki, Hazırda Bekletme, saat diliminizi açıkça ayarlamanıza olanak tanır.

İlk olarak, SessionFactory yapılandırılırken belirtilebilir:

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

İkincisi, saat dilimi belirtilebilirBelirli bir oturum için:

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

4.5 @TimeZoneStorage notu

Programcıların bir ülkede (ve bir saat diliminde) çalışmaya dayalı bir veritabanı tasarlamaya başladıkları ve ardından birkaç yıl sonra farklı saat dilimlerinde çalışmak için destek eklemeleri gerektiği sık sık olur.

Bu nedenle, saat dilimini saklamak için veritabanına ayrı bir sütun eklediler. Bu o kadar yaygın bir durumdur ki, Hazırda Bekletme, belirli bir tarihin Saat Dilimi'ni ayrı bir sütunda saklamanıza izin veren özel bir açıklama eklemiştir.

Örnek:

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

Bu bir koltuk değneği. Ancak bunun bir de bahanesi var: DateTime API'sinin henüz olmadığı bir zamanda ortaya çıktı. Ve TimeZone'u sınıfta saklamak imkansızdı java.util.Date.

Umarım bunu kodunuzda sık sık görmezsiniz.