Lo stato attuale delle cose nel tempo

Dal momento in cui JDBC è stato inventato e le sue interfacce sono state standardizzate, sono passati 20 anni e durante questo periodo molte cose sono cambiate.

In primo luogo, il mondo è diventato globale e ora un server può servire utenti da tutto il mondo. La velocità di Internet è aumentata. Pertanto, un altro tipo di dati è stato aggiunto a SQL per lavorare con il tempo. Ora i tipi hanno questo aspetto:

  • DATE - memorizza la data: anno, mese, giorno.
  • TIME - memorizza il tempo: ore, minuti, secondi.
  • TIMESTAMP - memorizza un punto specifico nel tempo: data, ora e millisecondi.
  • TIMESTAMP CON FUSO ORARIO - TIMESTAMP e fuso orario (nome o offset della zona).

In secondo luogo, Java ha introdotto l'API DateTime per la gestione del tempo globale. Ha le seguenti classi:

  • Data e ora :
    • Data locale
    • Ora locale
  • Momento esatto :
    • java.time.Instant
    • java.time.LocalDateTime
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime
  • Ora con fuso orario :
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime

Il terzo punto interessante è che molti client SQL vorrebbero ricevere l'ora dal server già nella loro zona locale . Certo, puoi convertire il tempo al volo, ma non è conveniente e ci sono errori.

Ad esempio, voglio ottenere tutte le attività per oggi dal database. SQL Server ha una funzione CURDATE() per questo. Solo qui il server è negli Stati Uniti e io sono in Giappone. E vorrei che restituisse tutti i record per "il mio oggi", e non per il "suo oggi".

In generale, il server SQL deve anche essere in grado di lavorare in modo intelligente con client in diversi fusi orari.

I problemi moderni richiedono soluzioni moderne

In linea di principio, è possibile mappare comodamente nuovi tipi dall'API Java DateTime e tipi da SQL. Per rappresentare il tipo DATE in Java, è necessario utilizzare la classe java.time.LocalDate dall'API JDK 8 DateTime.

Il tipo TIME dal database può essere rappresentato da due tipi da Java: java.time.LocalTime e java.time.OffsetTime . Niente di complicato neanche.

Un momento specifico, rappresentato dal tipo TIMESTAMP nel database, può essere rappresentato in Java da 4 tipi:

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

E infine, TIMESTAMP WITH TIME ZONE può essere rappresentato da due tipi:

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

Dato che hai già familiarità con l'API DateTime, ricordare questa questione non sarà difficile per te :)

Lo scriverò sotto forma di tabella, quindi sarà più facile:

TIPO SQL Tipo Java
DATA java.time.LocalDate
TEMPO java.time.LocalTime
java.time.OffsetTime
TIMESTAMP java.time.Instant
java.time.LocalDateTime
java.time.OffsetDateTime
java.time.ZonedDateTime
TIMESTAMP CON FUSO ORARIO java.time.OffsetDateTime
_

Ottenere la data

Ho una buona notizia per te. Prima da molto tempo. Possiamo aggirare la limitazione del metodo getDate() , che restituisce un tipo di data java.sql.

Il punto è che l'oggettoset di risultatic'è un altro metodo interessante: getObject() . Questo metodo accetta due parametri: una colonna e un tipo e restituisce il valore della colonna convertita nel tipo specificato. La forma generale del metodo è la seguente:

ClassName Name = getObject(column, ClassName);

E se vuoi convertire il tipo DATE nel tipo java.time.LocalDate , devi scrivere qualcosa del tipo:

LocalDate localDate = results.getObject(4, LocalDate.class);

E qualsiasi TIMESTAMP in generale può essere convertito in un gruppo di tipi:

java.time.Instant instant = results.getObject(9, java.time.Instant.class);
java.time.LocalDateTime local = results.getObject(9, java.time. LocalDateTime.class);
java.time.OffsetDateTime offset = results.getObject(9, java.time. OffsetDateTime.class);
java.time.ZonedDateTime zoned = results.getObject(9, java.time. ZonedDateTime.class);

Importante! Questo codice non funzionerà se si dispone di un driver MySQL JDBC obsoleto . Fai attenzione alla versione di "mysql-connector-java" scritta nel tuo pom.xml, o aggiunta alle Librerie nelle impostazioni del progetto.

A proposito, allo stesso modo, puoi aggirare l'impossibilità di memorizzare null per i tipi primitivi. Se una colonna della tabella è di tipo INT, allora ci sono un paio di modi per ottenere null da essa. Vedi l'esempio qui sotto:

Integer id1 = results.getObject(8, Integer.class);    	 // this will work
Integer id2 = results.getObject(8, int.class);                 //this will also work
int id3 = results.getObject(8,  Integer.class);            	//method will return null, JVM will throw NPE
int id4 = results.getObject(8,  int.class);                    	//method will return null, JVM will throw NPE

Impostazione del fuso orario in MySQL

Anche con MySQL sono successe molte cose interessanti. Come sai, quando crei una connessione MySQL, puoi aggiungere vari parametri ad essa :
mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning

Quindi, sono stati aggiunti tre parametri per lavorare con i fusi orari in MySQL. Puoi passare questi parametri quando stabilisci una connessione al server.

Di seguito darò un tavolo con loro:

Parametro Valori Valore di default
connessioneTimeZone LOCALE | SERVER | zona utente SERVER
forceConnectionTimeZoneToSession vero | falso VERO
preserveInstant vero | falso falso

Utilizzando il parametro connectionTimeZone , selezioniamo il fuso orario (fuso orario) in cui verranno eseguite tutte le richieste. Dal punto di vista del client, il server è in esecuzione nel fuso orario specificato.

Il parametro forceConnectionTimeZoneToSession fa sì che la variabile time_zone della sessione venga ignorata e sostituita con connectionTimeZone.

Infine, il parametro preserveInstants controlla la conversione dell'ora esatta tra timeZone e connectionTimeZone della JVM.

Le configurazioni più comuni sono:

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false - corrisponde al vecchio driver MySQL JDBC versione 5.1 con useLegacyDatetimeCode=true.

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true è una nuova modalità che fornisce il modo più naturale per gestire i valori di data e ora.

  • connectionTimeZone=SERVER & preserveInstants=true - Corrisponde al vecchio driver MySQL JDBC versione 5.1 con useLegacyDatetimeCode=false.

  • connectionTimeZone=user_defined & preserveInstants=true - Aiuta a superare la situazione in cui il fuso orario del server non può essere riconosciuto dal connettore perché è impostato come un'abbreviazione generica come CET/CEST.

Sì, le date sono un argomento interessante e ci sono molti problemi con loro. Come si suol dire: fa paura, certo, ma non sono nemmeno incazzato! :)