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

Sådan gemmer du et Java Instant i en MySQL-database

Trunker til mikrosekunder

Vi kan naturligvis ikke presse nanosekunderne opløsning af en Instant ind i mikroseconds opløsning af MySQL-datatyperne DateTime og Timestamp .

Selvom jeg ikke bruger MySQL, forestiller jeg mig JDBC-driveren er bygget til at ignorere nanosekunderne, når du modtager en Instant , afkorter værdien til mikrosekunder. Jeg foreslår, at du prøver et eksperiment for at se, og måske undersøger kildekoden til din driver, der overholder JDBC 4.2 og nyere.

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

…og…

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

JDBC 4.2-specifikationen kræver understøttelse af OffsetDateTime men kræver mærkeligt nok ikke de to mere almindeligt anvendte typer, Instant og ZonedDateTime . Hvis din JDBC-driver understøtter ikke Instant , konverter.

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`. 

Sammenlign derefter.

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

Du er klogt bekymret over værdier hentet fra databasen, der ikke matcher den oprindelige værdi. En løsning, hvis den er acceptabel for dit forretningsproblem, er at afkorte eventuelle nanosekunder til mikrosekunder i dine originale data. Jeg anbefaler generelt denne tilgang.

java.time klasser tilbyder en truncatedTo metode. Send en ChronoUnit enum-objekt for at angive granulariteten. I dette tilfælde ville det være ChronoUnit.MICROS .

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

I øjeblikket burde denne tilgang være tilstrækkelig, da du sandsynligvis ikke har nogen nanosekunder i dine data. Mainstream-computere i dag har ikke hardware-ure, der er i stand til at fange nanosekunder, så vidt jeg ved.

Tæl fra epoke

Hvis du ikke har råd til at miste nogen nanosekund-data, der måtte være til stede, skal du bruge en tælle-fra-epoke.

Jeg anbefaler normalt ikke at spore dato-tid som en optælling fra en epoke referencedato. Men du har få andre valg til at gemme dine nanosekund-baserede værdier i en database som MySQL og Postgres begrænset til mikrosekund-baserede værdier.

Gem par af heltal

I stedet for at bruge det ekstremt store antal nanosekunder siden en epoke som f.eks. 1970-01-01T00:00Z, foreslår jeg, at man følger den tilgang, som de interne af Instant har taget. klasse:Brug et par af tal.

Gem et antal hele sekunder som et heltal i din database. I en anden kolonne gemmes antallet af nanosekunder i brøksekundet som et heltal.

Du kan nemt udtrække/injicere disse numre fra/til et Instant objekt. Kun simpel 64-bit long tal er involveret; intet behov for BigDecimal eller BigInteger . Jeg formoder, at du måske kan bruge en 32-bit heltalskolonne til mindst et af de to tal. Men jeg ville vælge 64-bit heltals kolonnetyper for enkelhedens skyld og for direkte kompatibilitet med java.time.Instant klasses par longs.

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

…og…

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

Når du sorterer kronologisk, skal du udføre en sortering på flere niveauer, først sortere på hele sekunders kolonnen og derefter sortere sekundært på nanos-brøkdelen af ​​anden kolonne.




  1. Sådan fjerner du mellemrum fra en streng i MySQL

  2. Hvorfor du skal bruge PHPs PDO til databaseadgang

  3. JOIN-forespørgsler vs. flere forespørgsler

  4. Oracle:hvordan man trækker to datoer fra og får minutter af resultatet