如何在MySQL数据库中存储Java Instant

使用Java Date对象,最简单的方法是将它们存储为MySql DateTime对象(以UTC格式)。 切换到Instant这种方法将不再起作用,因为MySQL DateTime不提供存储纳秒的精度。 只是截断它们可能会导致新创建的Instant对象与从数据库中读取的对象之间出现意外的比较结果。

BigDecimal时间戳不会让我觉得它是一个优雅的解决方案:在MySql Workbench中编写select查询会变得更加困难,因为你必须在任何地方转换时间戳以使其可读,并且Java中的处理与Instant或甚至Long相比有点笨拙值。

什么是最好的方式去这里? 可能不是varchar ,对吗?

截断到微秒

显然,我们无法将Instant的纳秒分辨率压缩到MySQL数据类型DateTimeTimestamp的微秒分辨率。

我想构建JDBC驱动程序是为了在接收Instant时忽略纳秒,将值截断为微秒。 我建议您尝试一个实验来查看,并且可能会检查符合JDBC 4.2及更高版本的驱动程序的源代码。

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

…和…

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

然后比较。

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

您明智地担心从数据库中提取的值与原始值不匹配。 如果您的业务问题可以接受,一种解决方案是在原始数据中截断任何纳秒到微秒。 我一般推荐这种方法。

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

目前这种方法应该足够了,因为您的数据不太可能有纳秒。 据我所知,今天的主流计算机不具备能够捕获纳秒的硬件时钟。

从时代算起

如果您不能丢失任何可能存在的纳秒数据,请使用从纪元开始的计数。

我通常建议不要将日期时间作为纪元参考日期的计数。 但是,在将基于纳秒的值存储在MySQL和Postgres等数据库中的基于微秒的值中,您几乎没有其他选择。

存储一对整数

我建议遵循Instant类的内部方法:使用一数字,而不是使用自1970-01-01T00:00Z之类的纪元以来的极大数量的纳秒。

在数据库中将整数秒存储为整数。 在第二列存储中,以整数表示小数秒内的纳秒数。

您可以轻松地从/向Instant对象提取/注入这些数字。 只涉及简单的64位long数字; 不需要BigDecimalBigInteger 。 我想你可能能够为这两个数字中的至少一个使用32位整数列。 但为了简单起见,我会选择64位整数列类型,并与java.time.Instant类的long对直接兼容。

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

…和…

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

按时间顺序排序时,您需要进行多级排序,首先在整个秒列上排序,然后在纳秒级秒列上进行排序。