Спящий режим и статический запуск запросов HQL

Я хотел бы выполнить «пробный» Hibernate HQL-запросы. То есть я хотел бы знать, какие фактические запросы SQL Hibernate будет выполнять из данного запроса HQL без фактического выполнения запроса HQL к реальной базе данных.

У меня есть доступ к отображению гибернации для таблиц, строке запроса HQL, диалект для моей базы данных. У меня также есть доступ к базе данных, если это необходимо.

Теперь, как я могу узнать все SQL-запросы, которые Hibernate может сгенерировать из моего HQL, без фактического выполнения запроса к какой-либо базе данных? Есть ли для этого какие-нибудь инструменты?

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

Я не спрашиваю, как регистрировать SQL-запросы во время выполнения HQL-запроса.

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

Изменить: я также знаю, какие ограничения и смещения применяются к запросу. У меня также есть фактические параметры, которые будут привязаны к запросу.


person Juha Syrjälä    schedule 10.12.2009    source источник


Ответы (2)


Короткий ответ - «вы не можете». Подробный ответ ниже.

Вы можете использовать два подхода:

A) Загляните в HQLQueryPlan class , особенно его getSqlStrings() метод. Он не даст вам точного SQL, потому что перед фактическим выполнением запроса требуется дополнительная предварительная обработка (параметры привязаны, применяются ограничения / смещения и т. Д.), Но он может быть достаточно близок к тому, что вы хотеть.

Здесь следует иметь в виду, что вам понадобится реальный экземпляр SessionFactory для создания HQLQueryPlan, что означает, что вы не сможете сделать это без «подключения к любой базе данных». Однако вы можете использовать базу данных в памяти (SqlLite и тому подобное) и настроить Hibernate для автоматического создания для нее необходимой схемы.

Б) Начните с _5 _ И погрузиться в безумие AST / ANTLR. Теоретически вы можете создать синтаксический анализатор, который работал бы, не полагаясь на метаданные, но мне трудно представить, что вы пытаетесь сделать, чтобы это того стоило. Может у вас получится уточнить? Должен быть лучший подход.

person ChssPly76    schedule 10.12.2009

Обновление: для автономного пробного запуска некоторого HQL использование HQLQueryPlan напрямую является хорошим подходом. Если вы хотите перехватывать каждый запрос в приложении во время его работы и записывать SQL, вам придется использовать прокси и отражение, как описано ниже.

Взгляните на этот ответ для критериев запросов.

Для HQL это та же концепция - вы должны преобразовать классы реализации Hibernate и / или получить доступ к закрытым членам, поэтому это не поддерживаемый метод, но он будет работать с версиями Hibernate 3.2–3.3. Вот код для доступа к запросу из HQL (запрос - это объект, возвращаемый session.createQuery (hql_string):

Field f = AbstractQueryImpl.class.getDeclaredField("session");
f.setAccessible(true);
SessionImpl sessionImpl = (SessionImpl) f.get(query);
Method m = AbstractSessionImpl.class.getDeclaredMethod("getHQLQueryPlan", new Class[] { String.class, boolean.class });
m.setAccessible(true);
HQLQueryPlan plan = (HQLQueryPlan) m.invoke(sessionImpl, new Object[] { query.getQueryString(), Boolean.FALSE });
for (int i = 0; i < plan.getSqlStrings().length; ++i) {
  sql += plan.getSqlStrings()[i];
}

Я бы обернул все это в try / catch, чтобы вы могли продолжить запрос, если ведение журнала не работает.

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

person Brian Deterling    schedule 10.12.2009
comment
Вся эта возня с рефлексией совершенно не нужна. HQLQueryPlan имеет открытый конструктор; вам нужно только преобразовать фабрику сеансов в SessionFactoryImplementor. - person ChssPly76; 10.12.2009
comment
Верно, и после перечитывания его вопроса это, наверное, все, что ему нужно. Я обращался к ситуации, когда вы хотите фиксировать HQL / SQL для каждого запроса, выполняемого в вашем приложении в реальном времени - без необходимости изменять каждый класс в приложении, которое выполняет запрос. Поскольку у меня нет возможности удаления, я добавил строку для пояснения. - person Brian Deterling; 11.12.2009
comment
Справедливо; хотя, если все, что вы хотите сделать, это захватить SQL, вероятно, проще (и гораздо более вероятно, что вы переживете обновления Hibernate) написать простой аппендер и прикрепить его к org.hibernate.SQL :-) - person ChssPly76; 11.12.2009
comment
Соглашаться. Я позволяю ограничениям, которые у меня есть, раскрасить мои решения для проблем, для которых этих ограничений нет. Мне нужно было увидеть sql во время его работы, сохранить тайминги в базе данных, захватить параметры и количество результатов, сгруппировать несколько выполнений одного и того же запроса с одинаковыми параметрами и т. Д. Все излишки для этого вопроса. - person Brian Deterling; 11.12.2009