4.1 Excursus sa kasaysayan

Ang gawain ng pag-save ng mga bagay sa Java sa database ay may kaugnayan halos kaagad pagkatapos ng paglikha ng wikang Java. Noong panahong iyon, mayroon lamang isang uri ng data sa wikang Java, Petsa, na nag-imbak ng oras ayon sa pamantayan ng UNIX-time: bilang bilang ng mga millisecond mula noong 1970.

Well, sa mga database sa oras na iyon ay mayroon nang iba't ibang mga uri ng data para sa mga petsa, hindi bababa sa mayroong magkahiwalay na mga uri para sa petsa, oras at petsa + oras:

  • DATE
  • ORAS
  • TIMESTAMP

Samakatuwid, ang mga tagalikha ng wikang Java ay nagdagdag ng isang espesyal na pakete dito - java.sql, na naglalaman ng mga klase:

  • java.sql.date
  • java.sql.Oras
  • java.sql.timestamp

Ang pagmamapa sa mga klase na ito ay isang tunay na kasiyahan:


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

Ngunit dahil nagtatrabaho ang mga programmer sa klase java.util.Date, nagdagdag si Hibernate ng isang espesyal na anotasyon @Temporalupang makontrol ang pagmamapa ng uri ng Petsa.

Halimbawa:

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

Ang uri java.util.Calendarat java.util.Datedefault na uri ay gumagamit ng TIMESTAMP na uri upang katawanin ang mga ito sa database.

4.2 Bagong panahon

Sa kasalukuyan, sa pagmamapa, ang lahat ay mas simple at mas mahusay. Sinusuportahan ng lahat ng database ang 4 na uri ng data upang gumana sa oras:

  • DATE - petsa: taon, buwan at araw.
  • ORAS - oras: oras, minuto, segundo.
  • TIMESTAMP - petsa, oras at nanosecond.
  • TIMESTAMP WITH TIME ZONE - TIMESTAMP at time zone (pangalan ng zone o offset).

Upang kumatawan sa uri DATEsa Java, kailangan mong gumamit ng klase java.time.LocalDatemula sa JDK 8 DateTime API.

UriORASmula sa database ay maaaring kinakatawan ng dalawang uri mula sa Java: java.time.LocalTimeat java.time.OffsetTime. Walang kumplikado.

At ang eksaktong petsa at oras na kinakatawan ng uriTIMESTAMPsa base, sa Java maaari itong kinakatawan ng 4 na uri:

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

At sa wakasTIMESTAMP NA MAY TIME ZONEmaaaring kinakatawan ng dalawang uri:

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

Dahil pamilyar ka na sa DateTime API , ang pag-alala sa bagay na ito ay hindi magiging mahirap para sa iyo :)

Ang pagmamapa sa kanila ay purong kasiyahan:

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

Ang anotasyon @Basicay nangangahulugan na ang field ay dapat na awtomatikong maproseso : Ang hibernate ay magpapasya kung aling column at uri ang field na ito ay dapat na imapa.

4.3 Paggawa gamit ang mga time zone

Kung ang time zone ay bahagi ng isang petsa, kung gayon ang pag-iimbak ng mga ito sa database ay simple - tulad ng isang regular na petsa:

@Basic
private java.time.OffsetDateTime offsetDateTime;

@Basic
private java.time.ZonedDateTime zonedDateTime;

Gayunpaman, kung gusto mong mag-imbak ng mga timezone nang hiwalay sa petsa:

@Basic
private java.time.TimeZone timeZone;

@Basic
private java.time.ZoneOffset zonedOffset;

Pagkatapos ay iimbak sila ng Hibernate sa uri ng VARCHAR bilang default. Na, sa katunayan, ay lohikal, dahil ang TimeZone ay karaniwang may string na pangalan tulad ng "UTC + 3" o "Cairo".

4.4 Pagtatakda ng sarili mong time zone

Kapag nagtatrabaho ka sa pag-save ng mga petsa sa database, makikita mo ang katotohanan na mayroon nang 4 na lugar kung saan maaari mong itakda ang kasalukuyang time zone:

  • Operating system ng server;
  • DBMS;
  • Java application
  • Hibernate.

Kung hindi tinukoy ng DBMS ang isang time zone (TimeZone), kukunin ito mula sa mga setting ng operating system. Maaaring hindi ito maginhawa, dahil ang mga backup na DBMS ay madalas na matatagpuan sa iba pang mga data center na may sariling time zone.

Samakatuwid, halos lahat ng mga admin ng DBMS ay nagtakda ng isang solong zone upang ang data ay madaling mailipat mula sa isang server patungo sa isa pa.

Ang sitwasyon ay katulad ng isang Java application. Maaari rin itong patakbuhin sa iba't ibang mga server sa iba't ibang mga data center, kaya karaniwan itong may tahasang time zone.


java -Duser.timezone=UTC ...

O habang tumatakbo ang program:

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

At, siyempre, pinapayagan ka ng Hibernate na itakda nang tahasan ang iyong time zone.

Una, maaari itong tukuyin kapag kino-configure ang SessionFactory:

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

Pangalawa, maaaring tukuyin ang time zonepara sa isang partikular na sesyon:

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

4.5 @TimeZoneStorage annotation

Kadalasang nangyayari na nagsimula ang mga programmer sa pagdidisenyo ng database batay sa pagtatrabaho sa isang bansa (at isang time zone), at pagkatapos ng ilang taon kailangan nilang magdagdag ng suporta para sa pagtatrabaho sa iba't ibang time zone.

Samakatuwid, nagdagdag lamang sila ng isang hiwalay na column sa database upang iimbak ang time zone. Ito ay isang pangkaraniwang sitwasyon na ang Hibernate ay nagdagdag ng isang espesyal na anotasyon na nagbibigay-daan sa iyong iimbak ang TimeZone ng isang partikular na petsa sa isang hiwalay na column.

Halimbawa:

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

Ito ay isang saklay. Ngunit mayroon ding dahilan para dito: lumitaw ito sa panahong wala pa ang DateTime API. At imposibleng maimbak ang TimeZone sa klase java.util.Date.

Inaasahan ko na hindi mo ito madalas makita sa iyong code.