Автор оригинала: 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-запрос.