Рубрики
Без рубрики

Время ожидания запроса с помощью JPA и гибернации

Узнайте, как настроить период ожидания запроса и автоматически отменять медленно выполняемые запросы, используя подсказку запроса JPA или API для гибернации

Автор оригинала: Vlad Mihalcea.

Вступление

В этой статье мы рассмотрим, как лучше всего настроить интервал ожидания запроса с помощью JPA и гибернации.

Установка времени ожидания запроса позволяет отменить медленно выполняемые запросы, которые в противном случае оказали бы давление на ресурсы базы данных.

Тайм-аут запроса с JPA и гибернацией @vlad_mihalcea Узнайте больше: https://t.co/ijnTgcAKdF pic.twitter.com/D5hqTuvhiJ

“Явакс.настойчивость.запрос.тайм-аут” Подсказка по запросу JPA

Как я объяснил в этой статье , API сохранения Java определяет понятие подсказка запроса , которое, в отличие от того, что может предполагать его название, не имеет ничего общего с подсказками запроса базы данных. Подсказка запроса JPA-это опция настройки поставщика сохраняемости Java.

JPA обеспечивает поддержку установки интервала ожидания для данной сущности или SQL-запроса с помощью javax.persistence.запрос.тайм-аут подсказка по запросу:

List posts = entityManager
.createQuery(
    "select p " +
    "from Post p " +
    "where lower(p.title) like lower(:titlePattern)", Post.class)
.setParameter("titlePattern", "%Hibernate%")
.setHint("javax.persistence.query.timeout", 50)
.getResultList();

Значение тайм-аута определено в миллисекундах, поэтому приведенный выше запрос JPQL завершится через 50 миллисекунд, если только набор результатов не будет получен до порогового значения тайм-аута.

Подсказка запроса “org.hibernate.timeout” для перехода в спящий режим

Hibernate также предоставляет подсказку org.hibernate.timeout запроса, которая, в отличие от ее аналога JPA, занимает интервал ожидания в секундах:

List posts = entityManager
.createQuery(
    "select p " +
    "from Post p " +
    "where lower(p.title) like lower(:titlePattern)", Post.class)
.setParameter("titlePattern", "%Hibernate%")
.setHint("org.hibernate.timeout", 1)
.getResultList();

Свойство тайм-аута запроса Hibernate

Если вы развернете JPA javax.persistence.Запрос в режим гибернации org.hibernate.запрос.Интерфейс запроса , расширяющий спецификацию запроса JPA, позволяет получить доступ к методам расширения запросов Hibernate, которые позволяют задать комментарий на уровне SQL, подсказку или указать пороговое значение времени ожидания.

List posts = entityManager
.createQuery(
    "select p " +
    "from Post p " +
    "where lower(p.title) like lower(:titlePattern)", Post.class)
.setParameter("titlePattern", "%Hibernate%")
.unwrap(org.hibernate.query.Query.class)
.setTimeout(1)
.getResultList();

Точно так же, как это было в случае с подсказкой org.hibernate.timeout запроса, метод setTimeout использует интервал ожидания в секундах, поэтому приведенный выше запрос JPQL истечет через одну секунду, если запрос не завершится быстрее.

Время тестирования

Чтобы увидеть, как работает тайм-аут запроса, рассмотрим следующий пример:

List result = entityManager
.createNativeQuery(
    "SELECT 1 " +
    "FROM pg_sleep(2) ", Tuple.class)
.setHint(
    "javax.persistence.query.timeout", 
    (int) TimeUnit.SECONDS.toMillis(1)
)
.getResultList();

При выполнении запроса PostgreSQL выше база данных выдаст query_canceled исключение:

SELECT 1 
FROM pg_sleep(2)

-- SQL Error: 0, SQLState: 57014
-- ERROR: canceling statement due to user request

Автоматическое применение интервала ожидания для гибернации запросов

Если вы хотите автоматически применять время ожидания запроса ко всем запросам в режиме гибернации, вам следует передать JPA javax.persistence.запрос.тайм-аут подсказка запроса как свойство:


И затем вы выполняете следующий JPQL-запрос:

List posts = entityManager
.createQuery(
    "select p " +
    "from Post p " +
    "where function('1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(2) ) --',) is ''", Post.class)
.getResultList();

Затем Hibernate выдаст исключение тайм-аута запроса, даже если мы явно не указали интервал тайм-аута в запросе JPQL:

SELECT p.id AS id1_0_,
       p.title AS title2_0_
FROM post p
WHERE 1 >= ALL (
    SELECT 1
    FROM pg_locks, pg_sleep(2)
) --()=''

-- SQL Error: 0, SQLState: 57014
-- ERROR: canceling statement due to user request

Круто, правда?

Вывод

Установка интервала ожидания запроса очень полезна, так как в противном случае медленные выполняемые запросы будут удерживать соединение с базой данных, полученное в течение длительного периода времени, следовательно, оказывая давление на параллелизм и масштабируемость.