Я пытаюсь получить список записей между двумя Instant, используя Spring Data @Query.
/**
* Finds all the non-duplicate customers.
*
* @return The list of non-duplicate customers.
*/
//@formatter:off
@Query("SELECT c "
+ "FROM Customer c "
+ "WHERE c.isDuplicate = false "
+ " AND c.created BETWEEN :start AND :end "
+ "ORDER BY c.created")
//@formatter:on
List<Customer> findAllNonDuplicateCustomers(
@Param("start") Instant start,
@Param("end") Instant end
);
Во время тестирования я обнаружил, что:
this.customerRepository.findAllNonDuplicateCustomers(
Instant.MIN,
Instant.MAX
)
возвращает пустой список, но:
this.customerRepository.findAllNonDuplicateCustomers(
this.customers.get("rob").getCreated(),
this.customers.get("robba").getCreated()
)
возвращает желаемые результаты.
Сценарий тестирования:
Мой тест вставляет 6 клиентов во встроенную базу данных H2 и пытается выполнить запрос.
Поскольку Instant совместим и отлично работает для конкретных клиентов, неправильно ли использовать Instant.MIN и Instant.MAX для пограничного тестирования?
вот идея. Вы смотрите на SQL, вызванный провайдером JPA ...
SQL не поможет, поскольку он просто будет содержать параметры привязки. Но регистрация переданных значений может дать некоторое представление.





Я создал небольшой примерный проект и включил ведение журнала гибернаций для параметров привязки, что привело к следующему:
binding parameter [1] as [TIMESTAMP] - [-1000000000-01-01T00:00:00Z]
binding parameter [2] as [TIMESTAMP] - [+1000000000-12-31T23:59:59.999999999Z]
Как видно, аргументы передаются в базу данных без каких-либо изменений. База данных просто не может справиться с этим должным образом, но, очевидно, она может обрабатывать более «нормальные» значения.
Я бы счел это ошибкой или, по крайней мере, ограничением драйвера JDBC. Я также пробовал это с HSQLDB. Он имеет аналогичное ограничение, но вместо возврата пустых результатов выдает исключение.
Так что ты можешь сделать:
Отправить вопрос с H2. Они могут добавить проверку и выбросить исключение, но я сомневаюсь, что они добавят надлежащую поддержку.
Определите свои собственные значения MIN, MAX, которые действительно работают. После небольшого экспериментирования это, кажется, работает достаточно хорошо в том смысле, что H2 может справиться с этим, и трудно придумать реальные сценарии, в которых они находятся достаточно далеко в будущем / прошлом.
static final Instant CUSTOM_MIN = new Date(Long.MIN_VALUE / 2).toInstant();
static final Instant CUSTOM_MAX = new Date(Long.MAX_VALUE / 2).toInstant();
Заметки:
Не существует независимых от базы данных минимальных / максимальных дат.
Минимальные / максимальные значения java.util.Date здесь тоже не работают, но, очевидно, вдохновили меня на решение.
Я преобразовал java.time.Instant в java.sql.Timestamp, используя метод Timestamp.from (Instant). Я получил следующее: `Timestamp.from (Instant.MIN) = 169108098-07-03 21: 51: 43.0 Timestamp.from (Instant.MAX) = 169104627-12-11 11: 08: 15.999999999 Timestamp.from (Instant. now ()) = 2018-07-22 00: 46: 17.518 `
Продолжая предыдущий комментарий, когда я делаю present.after(past) –– где настоящее - это Timestamp.from (Instant.now ()), а прошлое - это Timestamp.from (Instant.MIN) –– я получаю false. Может ли это быть способствующим фактором? P.S. Документ javadoc для Timestamp # after (Timestamp) читает: Указывает, является ли этот объект Timestamp более поздним, чем данный объект Timestamp.
past.after(present) дает true.
# Продолжаем # Тем не менее, моделирование с помощью примера ниже Timestamp present_1 = Timestamp.from(Instant.now());Thread.sleep(1000);Timestamp present_2 = Timestamp.from(Instant.now());System.out.println("is present2 after present1 = " + present_2.after(present_1)); // trueSystem.out.println("is present1 after present2 = " + present_1.before(present_2)); // true дает ожидаемые результаты.
Поскольку H2 написан на Java, это может быть причиной, но это всего лишь предположение с моей стороны.
Мне это кажется ошибкой. В настоящее время я просто не уверен, виноваты ли в этом Spring Data, Hibernate или драйвер JDBC.