Автор оригинала: Vlad Mihalcea.
Вступление
В этой статье я покажу вам, как вы можете получить автоматически сгенерированный SQL-запрос из запроса сущности API критериев JPQL или JPA.
Регистрация инструкций SQL
Как я объяснил в этой статье , существует множество способов регистрации инструкций SQL, созданных JPA или Hibernate.
Например, механизм JDBC Источник данных прокси-сервер позволяет перехватывать и регистрировать все выполненные инструкции. Однако даже в этом случае вам необходимо проанализировать журнал и сопоставить запросы JPA с соответствующими инструкциями SQL.
Было бы намного проще, если бы существовал инструмент, который мог бы извлекать SQL-запрос непосредственно из экземпляра JPA Query .
Проекты типов гибернации
Проект с открытым исходным кодом Hibernate Types предоставляет множество дополнений для Hibernate ORM.
В то время как большинство разработчиков знают его для дополнительных пользовательских типов, таких как JSON , МАССИВ , интервал , IP , проект Hibernate Types также предлагает множество других утилит.
Например, существует стратегия именования Hibernate, которая позволяет сопоставлять свойства сущности Java camelCase с именами столбцов snake_case.
И это еще не все. Преобразователь результатов списка позволяет преобразовать проекцию запроса по умолчанию с помощью лямбд Java 8.
Начиная с версии 2.9.11, проект Hibernate Types предлагает утилиту SQLExtractor , которая позволяет получать SQL-запрос из любого запроса JPQL или API критериев, независимо от того, используете ли вы Hibernate 5.4, 5.3, 5.2, 5.1, 5.0, 4.3, 4.2, или 4.1.
Получите инструкцию SQL из запроса JPQL
Давайте предположим, что у нас есть следующий JPQL-запрос:
Query jpql = entityManager.createQuery("""
select
YEAR(p.createdOn) as year,
count(p) as postCount
from
Post p
group by
YEAR(p.createdOn)
""", Tuple.class
);
С типами Hibernate извлечение SQL-запроса, сгенерированного в режиме гибернации, так же просто:
String sql = SQLExtractor.from(jpql);
И, если мы зарегистрируем извлеченный SQL-запрос:
LOGGER.info("""
The JPQL query: [
{}
]
generates the following SQL query: [
{}
]
""",
jpql.unwrap(org.hibernate.query.Query.class).getQueryString(),
sql
);
Мы получаем следующий результат:
- The JPQL query: [
select
YEAR(p.createdOn) as year,
count(p) as postCount
from
Post p
group by
YEAR(p.createdOn)
]
generates the following SQL query: [
SELECT
extract(YEAR FROM sqlextract0_.created_on) AS col_0_0_,
count(sqlextract0_.id) AS col_1_0_
FROM
post p
GROUP BY
extract(YEAR FROM p.created_on)
]
Блестяще!
Обратите внимание, что мы развернули JPA Запрос в режим гибернации org.hibernate.запрос.Интерфейс запроса , который предоставил метод getQueryString , который мы можем использовать для регистрации связанной строки запроса JPQL.
Получите инструкцию SQL из запроса API критериев JPA
SQL-экстрактор не ограничивается запросами JPQL. Вы также можете использовать его с запросами API критериев, как показано в следующем примере:
CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuerycriteria = builder.createQuery(PostComment.class); Root postComment = criteria.from(PostComment.class); Join post = postComment.join("post"); criteria.where( builder.like(post.get("title"), "%Java%") ); criteria.orderBy( builder.asc(postComment.get("id")) ); Query criteriaQuery = entityManager.createQuery(criteria); String sql = SQLExtractor.from(criteriaQuery); assertNotNull(sql); LOGGER.info(""" The Criteria API, compiled to this JPQL query: [ {} ] generates the following SQL query: [ {} ] """, criteriaQuery.unwrap(org.hibernate.query.Query.class).getQueryString(), sql );
При выполнении приведенного выше тестового случая мы получаем следующий SQL-запрос:
- The Criteria API, compiled to this JPQL query: [
select
pc
from
PostComment as pc
inner join
pc.post as p
where
p.title like :param0
order by
pc.id asc
]
generates the following SQL query: [
SELECT
pc.id AS id1_1_,
pc.post_id AS post_id3_1_,
pc.review AS review2_1_
FROM
post_comment pc
INNER JOIN
post p ON pc.post_id=p.id
WHERE
p.title LIKE ?
ORDER BY
pc.id ASC
]
API критериев сначала компилируется в запрос JPQL, как показано в вызове метода getQueryString () .
Промежуточный запрос JPQL далее преобразуется в SQL-запрос, который правильно решается утилитой SQL Extractor .
Круто, правда?
Вывод
Получение SQL – запроса, связанного с запросом API критериев JPQL или JPA, является очень полезной функцией. И вы можете использовать для проверки автоматически сгенерированных SQL-запросов даже без запуска JPA Запроса .
Хотя вы также можете извлечь SQL-запрос из журнала приложений, SQLExtractor позволяет объединить JPA и SQL-запросы, чтобы создать сообщение журнала, содержащее оба запроса. И, если вы используете механизм медленного ведения журнала запросов, вы можете затем сопоставить запрос JPQL или API критериев, который сгенерировал конкретный медленный SQL-запрос.