4.1 Keçmişə ekskursiya
Java obyektlərini verilənlər bazasına saxlamaq məsələsi, demək olar ki, Java dili yaradılarkən aktual idi. O zaman Java dilində yalnız bircə məlumat tipi var idi - Date, UNIX-time standartına görə vaxtı saxlayırdı: 1970-ci ildən bəri keçən millisekundların sayı kimi.
Verilənlər bazasında isə həmin dövrdə tarixlərlə iş üçün artıq müxtəlif məlumat tipləri var idi, ən azından tarix, vaxt və tarix+vaxt üçün ayrı tiplər mövcud idi:
- DATE
- TIME
- TIMESTAMP
Ona görə də Java dili yaradıcıları xüsusi bir paket – java.sql əlavə etdilər ki, burada siniflər var idi:
- java.sql.Date
- java.sql.Time
- java.sql.Timestamp
Belə sinifləri məppinq etmək çox əyləncəlidir:
@Entity
public class TemporalValues {
@Basic
private java.sql.Date sqlDate;
@Basic
private java.sql.Time sqlTime;
@Basic
private java.sql.Timestamp sqlTimestamp;
}
Amma əvvəlki proqramçılar java.util.Date
sinifi ilə işləməli olduqlarına görə, Hibernate-də xüsusi annotasiya @Temporal
əlavə etdilər ki, Date tipinin məppinqinə nəzarət etmək mümkün olsun.
Nümunə:
// Əgər annotasiya olmasa, bazada TIMESTAMP tipi olacaq
Date dateAsTimestamp;
@Temporal(TemporalType.DATE) // DATE tipinə məppinq olunacaq
Date dateAsDate;
@Temporal(TemporalType.TIME) // TIME tipinə məppinq olunacaq
Date dateAsTime;
java.util.Calendar
və java.util.Date
tipləri üçün məlumat bazasında təqdim edilməsi üçün TIMESTAMP tipindən istifadə olunur.
4.2 Müasir dövr
Müasir zamanda məppinq ilə əlaqədar hər şey daha sadə və rahatdır. Bütün verilənlər bazaları zamanla işləmək üçün 4 məlumat tipini dəstəkləyir:
- DATE – tarix: il, ay və gün.
- TIME – vaxt: saat, dəqiqə, saniyə.
- TIMESTAMP – tarix, vaxt və nanosaniyə.
- TIMESTAMP WITH TIME ZONE – TIMESTAMP və zaman zonası (zona adı və ya ofset).
Java-da DATE tipini təqdim etmək üçün JDK 8 DateTime API-dan java.time.LocalDate
sinifindən istifadə etmək lazımdır.
Məlumat bazasından olan TIME tipini Java-nın iki tipi ilə təqdim etmək mümkündür: java.time.LocalTime
və java.time.OffsetTime
. Çətin bir şey yoxdur.
Məlumat bazasındakı TIMESTAMP tipini dəqiq tarix və vaxtla təqdim etmək üçün Java-dan 4 tip mövcuddur:
- java.time.Instant
- java.time.LocalDateTime
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Və nəhayət, TIMESTAMP WITH TIME ZONE iki tip ilə təqdim etmək mümkündür:
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Sən artıq DateTime API ilə tanış olduğuna görə, bunu yadda saxlamaq çətin olmayacaq :)
Məppinq etmək çox əyləncəlidir:
@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;
@Basic
annotasiyası, sahənin avtomatik işlənməli olduğunu göstərir: Hibernate, hansı sütun və tipə məppinq olunacağını özü qərar verir.
4.3 Zaman zonaları ilə iş
Əgər zaman zonası tarixin bir hissəsidirsə, onları bazada saxlamaq asandır – sadəcə adi tarix kimi:
@Basic
private java.time.OffsetDateTime offsetDateTime;
@Basic
private java.time.ZonedDateTime zonedDateTime;
Ancaq zaman zonalarını tarixdən ayrı saxlamaq istəyirsənsə:
@Basic
private java.time.TimeZone timeZone;
@Basic
private java.time.ZoneOffset zonedOffset;
O zaman Hibernate onları default olaraq VARCHAR tipində saxlayacaq. Bu da məntiqli, çünki TimeZone adətən "UTC+3" ya da "Cairo" kimi mətn adını daşıyır.
4.4 Öz zaman zonanı təyin etmək
Məlumat bazasına tarixləri saxlamaqla çalışanda, cari zaman zonasını təyin edə biləcəyin 4 yer var ki, onları nəzərə almalısan:
- Serverin əməliyyat sistemi;
- Verilənlər Bazası İdarəetmə Sistemi (DBMS);
- Java tətbiqi;
- Hibernate.
Əgər DBMS-də zaman zonası (TimeZone) qeyd edilməyibsə, o, onu əməliyyat sisteminin tənzimləmələrindən götürəcək. Bu, uyğun olmaya bilər, çünki ehtiyat DBMS-lər çox vaxt fərqli məlumat mərkəzlərində yerləşdirilir, oraların fərqli zaman zonaları olur.
Ona görə də, demək olar ki, bütün DBMS adminləri birləşmiş zonanı təyin edir ki, məlumatlar bir serverdən digərinə asanlıqla köçürülə bilsin.
Java tətbiqində də oxşar vəziyyət var. O da müxtəlif serverlərdə, fərqli məlumat mərkəzlərində işə salına bilinir, buna görə də adətən ona zaman zonası açıq şəkildə təyin edilir.
java -Duser.timezone=UTC ...
Və ya proqramın iş zamanı:
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
Əlbəttə ki, Hibernate öz zaman zonanı açıq şəkildə təyin etməyə imkan verir.
Birinci növbədə, onu SessionFactory konfiqurasiyası zamanı qeyd edə bilərsən:
settings.put(
AvailableSettings.JDBC_TIME_ZONE,
TimeZone.getTimeZone("UTC")
);
İkincisi, zaman zonanı xüsusi sessiya üçün qeyd edə bilərsən:
Session session = sessionFactory()
.withOptions()
.jdbcTimeZone(TimeZone.getTimeZone("UTC"))
.openSession();
4.5 @TimeZoneStorage annotasiyası
Çox vaxt elə vəziyyət olur ki, proqramçılar bir ölkə (və bir zaman zonası) üçün verilənlər bazasını layihələşdirməyə başlayırlar, lakin bir neçə il sonra fərqli zaman zonalarında işləmək üçün dəstək əlavə etməyə ehtiyac yaranır.
Ona görə də, sadəcə olaraq, zaman zonası saxlamaq üçün bazaya xüsusi bir sütun əlavə edirlər. Bu o qədər tez-tez rastlanan bir vəziyyətdir ki, Hibernate hər hansı bir vaxtın TimeZone-nu ayrıca bir sütunda saxlamağa imkan verən xüsusi annotasiya əlavə etdi.
Nümunə:
@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 növ çarədir. Amma bu da haqlıdır: O, DateTime API hələ mövcud olmadığı zamanlarda meydana gəldi. java.util.Date
sinifində TimeZone saxlamaq mümkün deyildi.
Ümid edirəm ki, belə bir şeyi kodunda tez-tez görməyəcəksən.
GO TO FULL VERSION