Mysql
 sql >> Datenbank >  >> RDS >> Mysql

So speichern Sie einen Java Instant in einer MySQL-Datenbank

Auf Mikrosekunden kürzen

Offensichtlich können wir die Nanosekunden nicht quetschen Auflösung eines Instant in die Mikrosekunden Auflösung der MySQL-Datentypen DateTime und Timestamp .

Obwohl ich MySQL nicht verwende, stelle ich mir den JDBC-Treiber vor wurde entwickelt, um die Nanosekunden beim Empfang eines Instant zu ignorieren , wodurch der Wert auf Mikrosekunden gekürzt wird. Ich schlage vor, dass Sie ein Experiment durchführen, um den Quellcode Ihres Treibers zu sehen und vielleicht zu untersuchen, der mit JDBC 4.2 und höher kompatibel ist.

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

…und…

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

Die JDBC 4.2-Spezifikation erfordert Unterstützung für OffsetDateTime erfordert aber seltsamerweise nicht die beiden häufiger verwendeten Typen Instant und ZonedDateTime . Wenn Ihr JDBC-Treiber unterstützt Instant nicht , konvertieren.

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

Dann vergleichen.

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

Sie sind vernünftigerweise besorgt darüber, dass aus der Datenbank gezogene Werte nicht mit dem ursprünglichen Wert übereinstimmen. Eine Lösung, sofern dies für Ihr Geschäftsproblem akzeptabel ist, besteht darin, alle Nanosekunden in Ihren Originaldaten auf Mikrosekunden zu kürzen. Ich empfehle diesen Ansatz allgemein.

Die java.time Klassen bieten einen truncatedTo Methode. Übergeben Sie eine ChronoUnit enum-Objekt, um die Granularität anzugeben. In diesem Fall wäre das ChronoUnit.MICROS .

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

Derzeit sollte dieser Ansatz ausreichen, da Sie wahrscheinlich keine Nanosekunden in Ihren Daten haben. Mainstream-Computer haben heute keine Hardware-Uhren, die Nanosekunden erfassen können, soweit ich weiß.

Zählung ab Epoche

Wenn Sie es sich nicht leisten können, eventuell vorhandene Nanosekundendaten zu verlieren, verwenden Sie eine Zählung ab Epoche.

Ich rate normalerweise davon ab, Datum und Uhrzeit als Zählung von einem Epochenbezugsdatum zu verfolgen. Aber Sie haben nur wenige andere Möglichkeiten, Ihre Nanosekunden-basierten Werte in einer Datenbank wie MySQL und Postgres zu speichern, die auf Mikrosekunden-basierte Werte beschränkt sind.

Ganzzahlpaar speichern

Anstatt die extrem große Anzahl von Nanosekunden seit einer Epoche wie 1970-01-01T00:00Z zu verwenden, schlage ich vor, dem Ansatz zu folgen, der von den Interna des Instant verfolgt wird Klasse:Verwenden Sie ein Paar von Zahlen.

Speichern Sie eine Anzahl von ganzen Sekunden als Integer in Ihrer Datenbank. Speichern Sie in einer zweiten Spalte als Ganzzahl die Anzahl der Nanosekunden im Bruchteil einer Sekunde.

Sie können diese Zahlen einfach aus/in einen Instant extrahieren/injizieren Objekt. Nur einfache 64-Bit long Zahlen sind beteiligt; keine Notwendigkeit für BigDecimal oder BigInteger . Ich nehme an, Sie können möglicherweise eine 32-Bit-Ganzzahlspalte für mindestens eine der beiden Zahlen verwenden. Aber ich würde der Einfachheit halber und für die direkte Kompatibilität mit java.time.Instant 64-Bit-Integer-Spaltentypen wählen Klasse’ Paar Longs.

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

…und…

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

Wenn Sie chronologisch sortieren, müssen Sie eine mehrstufige Sortierung durchführen, zuerst nach der Spalte „ganze Sekunden“ und dann sekundär nach der Spalte „Nanos Bruchteile von Sekunden“.