sql >> Databasteknik >  >> RDS >> Mysql

Hur man lagrar en Java Instant i en MySQL-databas

Trunkera till mikrosekunder

Uppenbarligen kan vi inte klämma in nanosekunderna upplösning av en Instant till mikrosekunder upplösning av MySQL-datatyperna DateTime och Timestamp .

Även om jag inte använder MySQL, föreställer jag mig JDBC-drivrutinen är byggd för att ignorera nanosekunderna när du tar emot en Instant , trunkerar värdet till mikrosekunder. Jag föreslår att du provar ett experiment för att se, och kanske undersöker källkoden för din drivrutin som överensstämmer med JDBC 4.2 och senare.

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

…och…

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

JDBC 4.2-specifikationen kräver stöd för OffsetDateTime men kräver konstigt nog inte de två vanligare typerna, Instant och ZonedDateTime . Om din JDBC-drivrutin stöder inte Instant , konvertera.

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

Jämför sedan.

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

Du är klokt nog bekymrad över att värden hämtade från databasen inte matchar det ursprungliga värdet. En lösning, om den är acceptabel för ditt affärsproblem, är att trunkera eventuella nanosekunder till mikrosekunder i dina ursprungliga data. Jag rekommenderar detta tillvägagångssätt generellt.

java.time klasser erbjuder en truncatedTo metod. Skicka en ChronoUnit enum-objekt för att ange granulariteten. I det här fallet skulle det vara ChronoUnit.MICROS .

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

För närvarande bör detta tillvägagångssätt räcka eftersom du sannolikt inte har några nanosekunder i din data. Dagens vanliga datorer har inga hårdvaruklockor som kan fånga nanosekunder, så vitt jag vet.

Räkna från epok

Om du inte har råd att förlora någon nanosekundsdata som kan finnas, använd en räkne-från-epok.

Jag brukar rekommendera att inte spåra datum-tid som en räkning från ett epokreferensdatum. Men du har få andra val när det gäller att lagra dina nanosekundbaserade värden i en databas som MySQL och Postgres begränsade till mikrosekundsbaserade värden.

Lagra par med heltal

Istället för att använda det extremt stora antalet nanosekunder sedan en epok som 1970-01-01T00:00Z, föreslår jag att man följer det tillvägagångssätt som använts av internerna i Instant klass:Använd ett par av siffror.

Lagra ett antal hela sekunder som ett heltal i din databas. I en andra kolumn lagras antalet nanosekunder i bråksekunden som ett heltal.

Du kan enkelt extrahera/injicera dessa nummer från/till ett Instant objekt. Endast enkla 64-bitars long siffror är inblandade; inget behov av BigDecimal eller BigInteger . Jag antar att du kanske kan använda en 32-bitars heltalskolumn för minst ett av de två talen. Men jag skulle välja 64-bitars heltalskolumntyper för enkelhetens skull och för direkt kompatibilitet med java.time.Instant klassens långa par.

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

…och…

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

När du sorterar kronologiskt måste du sortera på flera nivåer, först sortera hela sekundkolumnen och sedan sortera i andra hand på nanos bråkdel-av-sekund-kolumnen.




  1. Gruppera efter med union mysql-valfråga

  2. Vad är den genomsnittliga lönen för en SQL-utvecklare?

  3. Hur man konfigurerar Tomcat för att ansluta till MySQL

  4. Vad är det bästa sättet att ansluta till en Mysql-databas i Delphi