我们有一个应用程序,它使用H2进行单元测试,使用Oracle 11进行集成测试。所有测试都使用Java 8进行传递。我们有一个Foo
表,使用SQL DDL created_at
时间戳{ {1}},我们在Oracle模式下使用Oracle和H2。
创建created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
很简单。我们在Java中创建一个时间戳:
Foo
然后我们使用SQL在表中插入一个新的final Instant createdAt = Instant.now();
行,使用时间戳和其他东西:
Foo
(我们执行小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 Foo
返回一个Foo
对象,假设它与数据库中的相同(因为我们只是插入它)。
我们有另一个查询来从数据库中读取值。在查询期间,我们从结果集中获取值,如下所示:
Instant
从我所看到的,没有什么神秘的。
我们从Java 8升级到Java 10.突然间,我们的单元测试因H2而失败。它会出现(除非我错了)Java now supports microsecond precision in Instant
,但H2必须以毫秒精度存储值,因此我们的断言与我们得到的断言不匹配;一个人将有return Timestamp.toInstant(resultSet.getTimestamp("created_at"));
微秒。 (参见H2 Issue #1178。)所以我们解决了截断到毫秒的问题:
000
我们的单元测试用于H2,我们运行与Oracle上的集成测试相同的测试:
assertThat(retrievedFoo.getCreatedAt().truncatedTo(MILLIS),
is(createdFoo.getCreatedAt().truncatedTo(MILLIS)));
等等,什么?我们检索的foo上的时间戳比创建时间晚 1毫秒怎么可能?我们截断到毫秒。即使Java 10上的Expected: is <2018-06-05T14:32:32.111Z>
but: was <2018-06-05T14:32:32.112Z>
比Oracle存储的精度更高,我们也会在毫秒之后丢弃所有内容。 Oracle的时间戳存储如何提前提前原始时间戳Instant
?