Как напечатать строку запроса со значениями параметров при использовании Hibernate
Можно ли в Hibernate печатать сгенерированные запросы SQL с реальными значениями вместо вопросительных знаков?
Как бы вы предложили печатать запросы с реальными значениями, если это невозможно с Hibernate API?
37 ответов
У меня работает с
logging.level.org.hibernate.SQL= DEBUG
logging.level.org.hibernate.type=TRACE
У меня были проблемы со всеми ответами здесь, ни один из них на самом деле не дал мне параметров для запроса Spring Data JPA, который передавался перечислением в качестве PK.
Гибернация 5.3
<!-- silence the noise -->
<Logger name="org.hibernate.search.engine.metadata.impl" additivity="false"/>
<Logger name="org.hibernate.boot.internal" additivity="false"/>
<Logger name="org.hibernate.engine.internal" additivity="false"/>
<Logger name="org.hibernate.engine.jdbc" additivity="false"/>
<Logger name="org.hibernate.engine.transaction" additivity="false"/>
<Logger name="org.hibernate.engine.loading.internal" additivity="false"/>
<Logger name="org.hibernate.engine.spi.CollectionEntry" additivity="false"/>
<Logger name="org.hibernate.engine.query.spi.HQLQueryPlan" additivity="false"/>
<Logger name="org.hibernate.engine.query.spi.QueryPlanCache" additivity="false"/>
<Logger name="org.hibernate.engine.spi.IdentifierValue" additivity="false"/>
<Logger name="org.hibernate.engine.spi.CascadingActions" additivity="false"/>
<Logger name="org.hibernate.engine.spi.ActionQueue" additivity="false"/>
<Logger name="org.jboss.logging"/>
<Logger name="org.hibernate.SQL" level="debug" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="trace" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Logger name="org.hibernate.engine" level="trace" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
с
hibernate.format_sql
установлен в
true
для красивой печати, это образец моего вывода
17:00:00,664 [TRACE] Named parameters: {1=DE} [main] org.hibernate.engine.spi.QueryParameters.traceParameters(QueryParameters.java:325)
17:00:00,671 [DEBUG]
select
countrysub0_.code as code1_23_,
countrysub0_1_.country_subdivision as country_1_61_
from
country_subdivision countrysub0_
left outer join
jurisdiction_country_subdivision countrysub0_1_
on countrysub0_.code=countrysub0_1_.jurisdiction
where
countrysub0_.code=? [main] org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:103)
Я пробовал просто установить
org.hibernate.engine.spi.QueryParameters
к
trace
, но по какой-то причине названные параметры продолжали молчать, поэтому вместо этого я отключил все остальное, что регистрировалось. Однако он, похоже, не регистрирует все параметры, поэтому мне все еще нужен
BasicBinding
журнал тоже.
hibernate-types имеет служебный метод для регистрации запросов 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
);
String sql = SQLExtractor.from(jpql);
sql
переменная имеет следующее значение:
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)
Его можно скопировать и вставить в консоль db как есть.
Если вы используете spring-boot, вы можете использовать зависимость log4jdbc-spring-boot-starter, которая является ответвлением org.bgee.log4jdbc-log4j2.
В
pom.xml
Я использовал следующую зависимость:
<dependency>
<groupId>com.integralblue</groupId>
<artifactId>log4jdbc-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
В документации упоминается, что если вы просто включите эту зависимость, ведение журнала SQL не будет работать, мы должны указать следующее свойство в application.properties
logging.level.jdbc.sqlonly=INFO
но с
2.0.0, для всех свойств ведения журнала по умолчанию задано значение info. на момент написания этого ответа количество использований для 2.0.0 меньше по сравнению с 1.0.2.
Таким образом, с 2.0.0, даже если вы не укажете никаких свойств для ведения журнала sql, следующие свойства устанавливаются по умолчанию.
logging.level.jdbc.sqlonly=INFO
logging.level.jdbc.resultset=INFO
logging.level.jdbc.connection=INFO
logging.level.jdbc.resultsettable=INFO
logging.level.jdbc.audit=INFO
logging.level.jdbc.sqltiming=INFO
Итак, если вы хотите, чтобы только SQL-запросы печатались с ? заменены фактическими значениями и избегают ненужного журнала из набора результатов, чтобы эти свойства явно
logging.level.jdbc.sqlonly=INFO
logging.level.jdbc.resultset=OFF
logging.level.jdbc.connection=OFF
logging.level.jdbc.resultsettable=OFF
logging.level.jdbc.audit=OFF
logging.level.jdbc.sqltiming=OFF
вы должны настроить, как показано ниже:
# Hibernate logging options (INFO only shows startup messages)
log4j.logger.org.hibernate=INFO
# Log JDBC bind parameter runtime arguments
log4j.logger.org.hibernate.type=trace
Если вы используете весеннюю загрузку и jpa
spring.jpa.properties.hibernate.show_sql=false
говорит спящий, чтобы скрыть логи
Похоже, истина по умолчанию!
Самым простым решением для меня является реализация обычного stringReplace для замены входных параметров на значения параметров (для простоты трактуя все параметры как строку):
String debugedSql = sql;
//then, for each named parameter
debugedSql = debugedSql.replaceAll(":"+key, "'"+value.toString()+"'");
//and finnaly
println(debugedSql);
или что-то подобное для позиционных параметров (?).
Позаботьтесь о пустых значениях и конкретных типах значений, таких как дата, если вы хотите, чтобы готовый SQL-файл был записан в журнал.