Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como armazenar um Java Instant em um banco de dados MySQL

Truncar para microssegundos


Obviamente, não podemos espremer os nanossegundos resolução de um Instant nos microssegundos resolução dos tipos de dados MySQL DateTime e Timestamp .

Embora eu não use MySQL, imagino o driver JDBC é construído para ignorar os nanossegundos ao receber um Instant , truncando o valor para microssegundos. Sugiro que você faça um experimento para ver e talvez examine o código-fonte do seu driver que está em conformidade com o JDBC 4.2 e posterior.
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 ) ;

A especificação JDBC 4.2 requer suporte para OffsetDateTime mas estranhamente não requer os dois tipos mais usados, Instant e ZonedDateTime . Se o seu driver JDBC não suporta Instant , converter.
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`. 

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

Você sabiamente se preocupa com os valores extraídos do banco de dados que não correspondem ao valor original. Uma solução, se aceitável para o seu problema de negócios, é truncar quaisquer nanossegundos para microssegundos em seus dados originais. Eu recomendo essa abordagem em geral.

O java.time classes oferecem um truncatedTo método. Passe um ChronoUnit enum objeto para especificar a granularidade. Nesse caso, seria ChronoUnit.MICROS .
Instant instant = Instant().now().truncatedTo( ChronoUnit.MICROS ) ;

Atualmente, essa abordagem deve ser suficiente, pois é improvável que você tenha nanossegundos em seus dados. Os computadores convencionais de hoje não possuem relógios de hardware capazes de capturar nanossegundos, até onde eu sei.

Contagem a partir da época


Se você não puder perder nenhum dado de nanossegundos que possa estar presente, use uma contagem de época.

Eu geralmente não recomendo o rastreamento de data e hora como uma contagem de uma data de referência de época. Mas você tem poucas outras opções para armazenar seus valores baseados em nanossegundos em um banco de dados, como MySQL e Postgres, limitado a valores baseados em microssegundos.

Armazenar par de inteiros


Em vez de usar o número extremamente grande de nanossegundos desde uma época como 1970-01-01T00:00Z, sugiro seguir a abordagem adotada pelos internos do Instant classe:use um par de números.

Armazenar um número de inteiros segundos como um inteiro em seu banco de dados. Em uma segunda coluna, armazene como um inteiro o número de nanossegundos no segundo fracionário.

Você pode facilmente extrair/injetar esses números de/para um Instant objeto. Apenas long simples de 64 bits números estão envolvidos; não há necessidade de BigDecimal ou BigInteger . Suponho que você possa usar uma coluna inteira de 32 bits para pelo menos um dos dois números. Mas eu escolheria tipos de colunas inteiras de 64 bits por simplicidade e compatibilidade direta com o java.time.Instant par de longs da classe.
long seconds = instant.getEpochSecond() ;
long nanos = instant.getNano() ;

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

Ao classificar cronologicamente, você precisará fazer uma classificação em vários níveis, classificando primeiro na coluna inteira de segundos e depois classificando secundariamente na coluna nanos de fração de segundo.