Как напечатать строку запроса со значениями параметров при использовании 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-файл был записан в журнал.

Другие вопросы по тегам