提问人:NotX 提问时间:11/9/2017 最后编辑:NotX 更新时间:12/10/2020 访问量:16399
如何在 MySQL 数据库中存储 Java Instant
How to store a Java Instant in a MySQL database
问:
对于 Java 对象,最简单的方法是将它们存储为 MySql 对象(以 UTC 为单位)。切换到这种方法将不再起作用,因为MySQL不提供存储纳秒的精度。仅仅截断它们可能会导致新创建的对象与从数据库读取的对象之间出现意外的比较结果。Date
DateTime
Instant
DateTime
Instant
BigDecimal
在我看来,时间戳并不是一个优雅的解决方案:手动编写选择查询变得更加困难,因为你必须在任何地方转换时间戳以使其可读,而且与值相比,Java 中的处理有些笨拙。Instant
Long
最好的方式是什么?可能不是,对吧?varchar
答:
截断为微秒
显然,我们不能将 Instant
的纳秒分辨率压缩到 MySQL 数据类型 DateTime
和 Timestamp
的微秒分辨率中。
虽然我不使用 MySQL,但我认为 JDBC 驱动程序在接收 时会忽略纳秒,将值截断为微秒。我建议您尝试一个实验来查看,并可能检查符合 JDBC 4.2 及更高版本的驱动程序的源代码。Instant
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 ) ;
JDBC 4.2 规范需要支持,但奇怪的是,它不需要两种更常用的类型,即 .如果您的 JDBC 驱动程序不支持 ,请转换。OffsetDateTime
Instant
ZonedDateTime
Instant
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`.
然后比较。
Boolean result = instant.equals( instant2 ) ;
System.out.println( "instant: " + instant + " equals instant2: = " + instant2 + " is: " + result ) ;
您明智地担心从数据库中提取的值与原始值不匹配。如果业务问题可以接受,一种解决方案是将原始数据中的任何纳秒截断为微秒。我一般推荐这种方法。
java.time 类提供了一个 truncatedTo
方法。传递枚举对象以指定粒度。在本例中,这将是 ChronoUnit.MICROS
。ChronoUnit
Instant instant = Instant().now().truncatedTo( ChronoUnit.MICROS ) ;
目前,这种方法应该足够了,因为您的数据中不太可能有任何纳秒。据我所知,当今的主流计算机没有能够捕获纳秒的硬件时钟。
从纪元开始计数
如果您无法承受丢失可能存在的任何纳秒数据,请使用 count-from-epoch。
我通常建议不要将日期时间作为纪元参考日期的计数进行跟踪。但是,在将基于纳秒的值存储在数据库(如 MySQL 和 Postgres)中时,您几乎没有其他选择,仅限于基于微秒的值。
存储整数对
与其使用自 1970-01-01T00:00Z 等纪元以来的大量纳秒,我建议遵循类内部所采用的方法:使用一对数字。Instant
在数据库中以整数形式存储整数秒数。在第二列中,以小数秒为单位的纳秒数存储为整数。
您可以轻松地从对象中提取/注入这些数字。仅涉及简单的 64 位数字;不需要 或 .我想您可能能够对两个数字中的至少一个使用 32 位整数列。但为了简单起见,我会选择 64 位整数列类型,并与类的 long 对直接兼容。Instant
long
BigDecimal
BigInteger
java.time.Instant
long seconds = instant.getEpochSecond() ;
long nanos = instant.getNano() ;
...和。。。
Instant instant = Instant.ofEpochSecond( seconds , nanos ) ;
按时间顺序排序时,您需要进行多级排序,首先对整个秒列进行排序,然后对纳米秒的分数列进行第二次排序。
评论
Instant
Instant
OffsetDateTime
ZoneOffset.UTC
uuuu-MM-dd'T'HH:mm.ss.SSSSSSSSSX
Instant
Instant
Instant
Instant