У нас есть приложение, в котором есть модульные тесты с использованием H2 и интеграционные тесты с использованием Oracle 11. Все тесты проходили с использованием Java 8. У нас есть таблица Foo
с отметкой времени created_at
с использованием SQL DDL created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
, котораямы используем как Oracle, так и H2 в режиме Oracle.
Создать Foo
просто.Мы создаем метку времени в Java:
final Instant createdAt = Instant.now();
Затем у нас есть SQL для вставки новой строки 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));
Следует помнить одну вещь: когда мы помещаем Foo
в базу данных, мы больше не запрашиваем значение;мы возвращаем Foo
объект, используя переданную нам Java Instant
, предполагая, что он такой же, как в базе данных (потому что мы только что вставили его).
У нас есть другой запрос для чтения значения избаза данных.Во время запроса мы получаем значение из результирующего набора, например:
return Timestamp.toInstant(resultSet.getTimestamp("created_at"));
Ничего загадочного, насколько я вижу,
Мы обновились с Java 8 до Java 10. Внезапно нашмодульные тесты провалились с H2.Может показаться (если я не ошибаюсь), что Java теперь поддерживает микросекундную точность в Instant
, но H2 должен был хранить значения с точностью до миллисекунды, поэтому наши утверждения не будут соответствовать тому, что мы получили обратно;один будет иметь 000
для микросекунд.(См. H2 Issue # 1178 .) Итак, мы решили, что мое усечение до миллисекунд:
assertThat(retrievedFoo.getCreatedAt().truncatedTo(MILLIS),
is(createdFoo.getCreatedAt().truncatedTo(MILLIS)));
С нашими модульными тестами, работающими на H2, мы выполнили те же тесты, что и интеграционные тесты наОракул:
Expected: is <2018-06-05T14:32:32.111Z>
but: was <2018-06-05T14:32:32.112Z>
Подождите, что?Временная метка для foo, которую мы получили , была на одну миллисекунду позже , чем время создания?Как это возможно?Мы обрезали до миллисекунд.Даже если Instant
в Java 10 обладает большей точностью, чем хранит Oracle, мы отбросили все за миллисекунды.Как хранилище меток времени Oracle получает впереди оригинальной метки времени Instant
?