我们有一个应用程序,它使用H2进行单元测试,使用Oracle 11进行集成测试。所有测试都通过了Java 8。我们有一个
Foo
有一个
created_at
使用SQL DDL的时间戳
created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
,我们在Oracle上和在Oracle模式下的H2上都使用它。
创建
福
很简单。我们用Java创建一个时间戳:
final Instant createdAt = Instant.now();
然后我们用SQL插入一个新的
福
使用时间戳和其他东西将行放入表中:
INSERT INTO Foo (uuid, name, created_at, bar_id)
SELECT ?, ?, ?, id FROM Bar WHERE Bar.name = ?;
(我们做的很少
SELECT
确保匹配的技巧
Bar
我们按名称查找,但这与时间戳无关。)
在准备好的语句中填写时间戳很容易:
preparedStatement.setTimestamp(3, Timestamp.from(createdAt));
有一件事需要注意
福
在数据库中,我们不再查询该值;我们返回
福
使用Java的对象
Instant
传递给我们,假设它与数据库中的相同(因为我们刚刚插入了它)。
我们有另一个查询从数据库中读取值。在查询过程中,我们从结果集中获取值,如下所示:
return Timestamp.toInstant(resultSet.getTimestamp("created_at"));
从我看来,没有什么神秘的。
我们从Java 8升级到Java 10。突然我们的单元测试因H2而失败。看起来(除非我错了)是
Java now supports microsecond precision in
Instant
,但是H2必须以毫秒精度存储值,所以我们的断言与我们得到的结果不匹配;其中一个
000
微秒。(见H2
Issue #1178
)所以我们把截短到毫秒:
assertThat(retrievedFoo.getCreatedAt().truncatedTo(MILLIS),
is(createdFoo.getCreatedAt().truncatedTo(MILLIS)));
在H2上运行单元测试时,我们运行的测试与Oracle上的集成测试相同:
Expected: is <2018-06-05T14:32:32.111Z>
but: was <2018-06-05T14:32:32.112Z>
等等,什么?foo上的时间戳我们
恢复
是一毫秒
后来
比创造的时间?怎么可能呢?我们缩短到毫秒。即使
瞬间
在Java 10上的精度比Oracle存储的要高,我们在几毫秒后就删除了所有内容。Oracle的时间戳存储是如何获得的
向前地
原始时间戳的
瞬间
?