java instant 在mysql,如何在MySQL数据库中存储Java Instant

当从Java的Instant对象转换到MySQL的DateTime类型时,由于DateTime不支持纳秒精度,可能导致数据丢失。建议将Instant对象截断到微秒级别以避免精度问题。文章讨论了手动截断可能带来的比较问题,并提出了存储整数秒和纳秒两个字段的解决方案,以保持数据完整性和查询便捷性。同时,建议在读取数据库时检查源代码,确保JDBC驱动在处理Instant时正确处理纳秒部分。
摘要由CSDN通过智能技术生成

With Java Date objects the easiest way to go was to store them as MySql DateTime objects (in UTC). With the switch to Instant this approach won't work anymore because MySQL DateTime does not offer the precision to store nanoseconds. Just truncating them could lead to unexpected comparison results between a newly created Instant objects and the ones read from the database.

BigDecimal timestamps don't strike me as an elegant solution: writing select queries manually becomes more difficult because you have to convert the timestamp everywhere to make it readable, and the handling in Java is somewhat clunky compared to Instant or even Long values.

What's the best way to go here? Probably not varchar, right?

解决方案

Truncate to microseconds

Obviously we cannot squeeze the nanoseconds resolution of an Instant into the microseconds resolution of the MySQL data types DateTime and Timestamp.

I imagine the JDBC driver is built to ignore the nanoseconds when receiving an Instant, truncating the value to microseconds. I suggest you try an experiment to see, and perhaps examine source code of your driver that complies with JDBC 4.2 and later.

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

…and…

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

Then compare.

Boolean result = instant.equals( instant2 ) ;

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

You wisely are concerned about values drawn from the database not matching the original value. One solution, if acceptable to your business problem, is to truncate any nanoseconds to microseconds in your original data. I recommend this approach generally.

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

Currently this approach should suffice as you are unlikely to have any nanoseconds in your data. Mainstream computers today do not sport hardware clocks capable of capturing nanoseconds, as far as I know.

Count from epoch

If you cannot afford to lose any nanosecond data that may be present, use a count-from-epoch.

I usually recommend against tracking date-time as a count from an epoch reference date. But you have few other choices in storing your nanosecond-based values in a database such as MySQL and Postgres limited to microsecond-based values.

Store pair of integers

Rather than using the extremely large number of nanoseconds since an epoch such as 1970-01-01T00:00Z, I suggest following the approach taken by the internals of the Instant class: Use a pair of numbers.

Store a number of whole seconds as an integer in your database. In a second column store as an integer the number of nanoseconds in the fractional second.

You can easily extract/inject these numbers from/to an Instant object. Only simple 64-bit long numbers are involved; no need for BigDecimal or BigInteger. I suppose you might be able to use a 32-bit integer column for at least one of the two numbers. But I would choose 64-bit integer column types for simplicity and for direct compatibility with the java.time.Instant class’ pair of longs.

long seconds = instant.getEpochSecond() ;

long nanos = instant.getNano() ;

…and…

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

When sorting chronologically, you'll need to do a multi-level sort, sorting first on the whole seconds column and then sorting secondarily on the nanos fraction-of-second column.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值