Mysql
 sql >> Database >  >> RDS >> Mysql

Come memorizzare un Java Instant in un database MySQL

Tronca a microsecondi

Ovviamente non possiamo spremere i nanosecondi risoluzione di un Instant nei microsecondi risoluzione dei tipi di dati MySQL DateTime e Timestamp .

Anche se non utilizzo MySQL, immagino il driver JDBC è costruito per ignorare i nanosecondi quando si riceve un Instant , troncando il valore in microsecondi. Ti suggerisco di provare un esperimento per vedere e magari esaminare il codice sorgente del tuo driver conforme a JDBC 4.2 e versioni successive.

Instant instant = Instant.now().with( ChronoField.NANO_OF_SECOND , 123_456_789L ) ;  //Set the fractional second to a spefic number of nanoseconds.
myPreparedStatement.setObject( … , instant ) ;

…e…

Instant instant2 = myResultSet.getObject( … , Instant.class ) ;

Le specifiche JDBC 4.2 richiede il supporto per OffsetDateTime ma stranamente non richiede i due tipi più comunemente usati, Instant e ZonedDateTime . Se il tuo driver JDBC non supporta Instant , converti.

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;  // Use `OffsetDateTime` if your JDBC driver does not support `Instant`. 
Instant instant2 = odt.toInstant() ;  // Convert from `OffsetDateTime` to `Instant`. 

Quindi confronta.

Boolean result = instant.equals( instant2 ) ;
System.out.println( "instant: " + instant + " equals instant2: = " + instant2 + " is: " + result ) ;

Sei saggiamente preoccupato per i valori estratti dal database che non corrispondono al valore originale. Una soluzione, se accettabile per il tuo problema aziendale, è troncare qualsiasi nanosecondo a microsecondi nei dati originali. Consiglio questo approccio in generale.

Il java.time le classi offrono un truncatedTo metodo. Passa un ChronoUnit enum per specificare la granularità. In questo caso, sarebbe ChronoUnit.MICROS .

Instant instant = Instant().now().truncatedTo( ChronoUnit.MICROS ) ;

Attualmente questo approccio dovrebbe essere sufficiente poiché è improbabile che tu abbia nanosecondi nei tuoi dati. I computer tradizionali oggi non sfoggiano orologi hardware in grado di catturare nanosecondi, per quanto ne so.

Conta dall'epoca

Se non puoi permetterti di perdere i dati di nanosecondi eventualmente presenti, utilizza un conteggio dall'epoca.

Di solito sconsiglio di tracciare la data e l'ora come conteggio da una data di riferimento di epoca. Ma hai poche altre scelte per archiviare i tuoi valori basati su nanosecondi in un database come MySQL e Postgres limitati a valori basati su microsecondi.

Memorizza coppia di numeri interi

Piuttosto che utilizzare il numero estremamente elevato di nanosecondi da un'epoca come 1970-01-01T00:00Z, suggerisco di seguire l'approccio adottato dagli interni di Instant classe:usa una coppia di numeri.

Archivia un certo numero di interi secondi come numero intero nel database. In una seconda colonna memorizza come numero intero il numero di nanosecondi nel secondo frazionario.

Puoi facilmente estrarre/iniettare questi numeri da/in un Instant oggetto. Solo semplice long a 64 bit i numeri sono coinvolti; non c'è bisogno di BigDecimal o BigInteger . Suppongo che potresti essere in grado di utilizzare una colonna intera a 32 bit per almeno uno dei due numeri. Ma sceglierei tipi di colonne intere a 64 bit per semplicità e per compatibilità diretta con java.time.Instant coppia di long della classe.

long seconds = instant.getEpochSecond() ;
long nanos = instant.getNano() ;

…e…

Instant instant = Instant.ofEpochSecond( seconds , nanos ) ;

Quando esegui l'ordinamento cronologico, dovrai eseguire un ordinamento a più livelli, ordinando prima sull'intera colonna dei secondi e quindi ordinando secondariamente sulla colonna della frazione di secondo nanos.