Como imprimir uma string de consulta com valores de parâmetro ao usar o Hibernate

É possível no Hibernate imprimir consultas SQL geradas com valores reais em vez de pontos de interrogação?

Como você sugeriria imprimir consultas com valores reais se isso não for possível com a API do Hibernate?

Você precisa habilitar o log para as seguintes categorias:

  • org.hibernate.SQL – configurado para debug para registrar todas as instruções SQL DML à medida que são executadas
  • org.hibernate.type – definido para trace para registrar todos os parâmetros JDBC

Então, uma configuração do log4j poderia se parecer com:

 # logs the SQL statements log4j.logger.org.hibernate.SQL=debug # Logs the JDBC parameters passed to a query log4j.logger.org.hibernate.type=trace 

O primeiro é equivalente a hibernate.show_sql=true legacy property , o segundo imprime os parâmetros ligados entre outras coisas.

Outra solução (não baseada em hibernação) seria usar um driver proxy JDBC como o P6Spy .

Apenas por conveniência, aqui está o mesmo exemplo de configuração para Logback (SLF4J)

  /tmp/sql.log  logFile.%d{yyyy-MM-dd}.log   %-4date | %msg %n           

A saída em seu sql.log (exemplo) se parece com isso:

 2013-08-30 18:01:15,083 | update stepprovider set created_at=?, lastupdated_at=?, version=?, bundlelocation=?, category_id=?, customer_id=?, description=?, icon_file_id=?, name=?, shareStatus=?, spversion=?, status=?, title=?, type=?, num_used=? where id=? 2013-08-30 18:01:15,084 | binding parameter [1] as [TIMESTAMP] - 2012-07-11 09:57:32.0 2013-08-30 18:01:15,085 | binding parameter [2] as [TIMESTAMP] - Fri Aug 30 18:01:15 CEST 2013 2013-08-30 18:01:15,086 | binding parameter [3] as [INTEGER] - 2013-08-30 18:01:15,086 | binding parameter [4] as [VARCHAR] - com.mypackage.foo 2013-08-30 18:01:15,087 | binding parameter [5] as [VARCHAR] - 2013-08-30 18:01:15,087 | binding parameter [6] as [VARCHAR] - 2013-08-30 18:01:15,087 | binding parameter [7] as [VARCHAR] - TODO 2013-08-30 18:01:15,087 | binding parameter [8] as [VARCHAR] - 2013-08-30 18:01:15,088 | binding parameter [9] as [VARCHAR] - MatchingStep@com.mypackage.foo 2013-08-30 18:01:15,088 | binding parameter [10] as [VARCHAR] - PRIVATE 2013-08-30 18:01:15,088 | binding parameter [11] as [VARCHAR] - 1.0 2013-08-30 18:01:15,088 | binding parameter [12] as [VARCHAR] - 32 2013-08-30 18:01:15,088 | binding parameter [13] as [VARCHAR] - MatchingStep 2013-08-30 18:01:15,089 | binding parameter [14] as [VARCHAR] - 2013-08-30 18:01:15,089 | binding parameter [15] as [INTEGER] - 0 2013-08-30 18:01:15,089 | binding parameter [16] as [VARCHAR] - 053c2e65-5d51-4c09-85f3-2281a1024f64 

Altere o hibernate.cfg.xml para:

 true true true 

Inclua inputs log4j e below em “log4j.properties”:

 log4j.logger.org.hibernate=INFO, hb log4j.logger.org.hibernate.SQL=DEBUG log4j.logger.org.hibernate.type=TRACE log4j.appender.hb=org.apache.log4j.ConsoleAppender log4j.appender.hb.layout=org.apache.log4j.PatternLayout 

Log4JDBC é uma boa solução que imprime o SQL exato indo para o database com parâmetros em lugar em lugar da resposta mais popular aqui que não faz isto. Uma grande conveniência disso é que você pode copiar o SQL diretamente para o seu front-end do DB e executá-lo como está.

http://log4jdbc.sourceforge.net/

https://code.google.com/p/log4jdbc-remix/

O último também gera uma representação tabular dos resultados da consulta.

Exemplo de saída mostrando o SQL gerado com parâmetros em conjunto com a tabela do conjunto de resultados da consulta:

 5. insert into ENQUIRY_APPLICANT_DETAILS (ID, INCLUDED_IN_QUOTE, APPLICANT_ID, TERRITORY_ID, ENQUIRY_ID, ELIGIBLE_FOR_COVER) values (7, 1, 11, 1, 2, 0) 10 Oct 2013 16:21:22 4953 [main] INFO jdbc.resultsettable - |---|--------|--------|-----------|----------|---------|-------| 10 Oct 2013 16:21:22 4953 [main] INFO jdbc.resultsettable - |ID |CREATED |DELETED |CODESET_ID |NAME |POSITION |PREFIX | 10 Oct 2013 16:21:22 4953 [main] INFO jdbc.resultsettable - |---|--------|--------|-----------|----------|---------|-------| 10 Oct 2013 16:21:22 4953 [main] INFO jdbc.resultsettable - |2 |null |null |1 |Country 2 |1 |60 | 10 Oct 2013 16:21:22 4953 [main] INFO jdbc.resultsettable - |---|--------|--------|-----------|----------|---------|-------| 

Atualize 2016

Mais recentemente eu tenho usado log4jdbc-log4j2 ( https://code.google.com/archive/p/log4jdbc-log4j2/ ) com SLF4j e logback. As dependencies do Maven necessárias para minha configuração são as seguintes:

  org.bgee.log4jdbc-log4j2 log4jdbc-log4j2-jdbc4.1 1.16   org.slf4j slf4j-api ${slf4j.version}   ch.qos.logback logback-core ${logback.version}   ch.qos.logback logback-classic $logback.version}  

O driver e os URLs do database são semelhantes a:

 database.driver.class=net.sf.log4jdbc.sql.jdbcapi.DriverSpy database.url=jdbc:log4jdbc:hsqldb:mem:db_name #Hsql database.url=jdbc:log4jdbc:mysql://localhost:3306/db_name #MySQL 

Meu arquivo de configuração logback.xml se parece com o abaixo: isso gera todas as instruções SQL com parâmetros, além das tabelas do conjunto de resultados para todas as consultas.

 < ?xml version="1.0" encoding="UTF-8"?>    %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n              

Finalmente, eu tive que criar um arquivo chamado log4jdbc.log4j2.properties na raiz do classpath, por exemplo, src / test / resources ou src / main / resources em um projeto Mevn. Este arquivo tem uma linha que é a abaixo:

 log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator 

O acima dependerá da sua biblioteca de logging. Consulte os documentos em https://code.google.com/archive/p/log4jdbc-log4j2 para mais informações

Exemplo de saída:

 10:44:29.400 [main] DEBUG jdbc.sqlonly - org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:70) 5. select memberrole0_.member_id as member_i2_12_0_, memberrole0_.id as id1_12_0_, memberrole0_.id as id1_12_1_, memberrole0_.member_id as member_i2_12_1_, memberrole0_.role_id as role_id3_12_1_, role1_.id as id1_17_2_, role1_.name as name2_17_2_ from member_roles memberrole0_ left outer join roles role1_ on memberrole0_.role_id=role1_.id where memberrole0_.member_id=104 10:44:29.402 [main] INFO jdbc.resultsettable - |----------|---|---|----------|--------|---|-----| |member_id |id |id |member_id |role_id |id |name | |----------|---|---|----------|--------|---|-----| |----------|---|---|----------|--------|---|-----| 

Você pode adicionar linhas de categoria ao log4j.xml:

    

e adicione propriedades de hibernação:

 true true true 

adicione as seguintes propriedades e valores à sua configuração log4j ou logback:

 org.hibernate.sql=DEBUG org.hibernate.type.descriptor.sql.BasicBinder=TRACE 

No caso de boot de mola estar sendo usado, basta configurar isto:

aplication.yml

 logging: level: org.hibernate.SQL: DEBUG org.hibernate.type: TRACE 

aplication.properties

 logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type=TRACE 

e nada mais.

HTH

ative o Registrador org.hibernate.type para ver como os parâmetros reais são ligados aos pontos de interrogação.

Você pode fazer isso usando o datasource-proxy , como descrevi neste post .

Supondo que seu aplicativo espera um bean dataSource (por exemplo, via @Resource ), é assim que você pode configurar o datasource-proxy :

         ${jdbc.username} ${jdbc.password} ${jdbc.url} ${jdbc.driverClassName}                    

Agora a saída do Hibernate vs o proxy da origem de dados:

 INFO [main]: ntdlCommonsQueryLoggingListener - Name:, Time:1, Num:1, Query:{[select company0_.id as id1_6_, company0_.name as name2_6_ from Company company0_][]} INFO [main]: ntdlCommonsQueryLoggingListener - Name:, Time:0, Num:1, Query:{[insert into WarehouseProductInfo (id, quantity) values (default, ?)][19]} INFO [main]: ntdlCommonsQueryLoggingListener - Name:, Time:0, Num:1, Query:{[insert into Product (id, code, company_id, importer_id, name, version) values (default, ?, ?, ?, ?, ?)][phoneCode,1,-5,Phone,0]} 

As consultas de datasource-proxy contêm valores de parâmetros e você pode até mesmo adicionar interceptores de instrução JDBC personalizados para que você possa capturar problemas de consulta N + 1 diretamente de seus testes de integração .

 **If you want hibernate to print generated sql queries with real values instead of question marks.** **add following entry in hibernate.cfg.xml/hibernate.properties:** show_sql=true format_sql=true use_sql_comments=true **And add following entry in log4j.properties :** log4j.logger.org.hibernate=INFO, hb log4j.logger.org.hibernate.SQL=DEBUG log4j.logger.org.hibernate.type=TRACE log4j.appender.hb=org.apache.log4j.ConsoleAppender log4j.appender.hb.layout=org.apache.log4j.PatternLayout 

                                      

Esta resposta é uma pequena variação para a questão. Às vezes, precisamos apenas do sql apenas para propósitos de debugging em tempo de execução. Nesse caso, há uma maneira mais fácil, usando a debugging nos editores.

  • Coloque um ponto de interrupção em org.hibernate.loader.Loader.loadEntityBatch (ou navegue na pilha até lá);
  • Quando a execução é suspensa, procure o valor da variável this.sql;

Isso é para o hibernate 3. Não tenho certeza se isso funciona em outras versões.

A solução está correta, mas registra também todas as ligações para os objects de resultado. Para evitar isso, é possível criar um appender separado e ativar a filtragem, por exemplo:

                                  

Eu gosto disso para log4j:

 log4j.logger.org.hibernate.SQL=trace log4j.logger.org.hibernate.engine.query=trace log4j.logger.org.hibernate.type=trace log4j.logger.org.hibernate.jdbc=trace log4j.logger.org.hibernate.type.descriptor.sql.BasicExtractor=error log4j.logger.org.hibernate.type.CollectionType=error 

              

Usando o Hibernate 4 e slf4j / log4j2, eu tentei adicionar o seguinte na minha configuração log4j2.xml:

       

Mas sem sucesso.

Eu descobri através deste thread que o framework jboss-logging usado pelo hibernate precisava ser configurado para logar através do slf4j. Eu adicionei o seguinte argumento aos argumentos da VM do aplicativo:

 -Dorg.jboss.logging.provider=slf4j 

E funcionou perfeitamente.

O driver jdbc do mysql já proveu um conveniente para atender a este requisito, você deve pelo menos ter a versão do jar> = mysql-connect-jar-5.1.6.jar

passo 1: [configure seu jdbc.url para adicionar logger e log customizado]

  jdbc.url=jdbc:mysql://host:port/your_db?logger=com.mysql.jdbc.log.Slf4JLogger&profileSQL=true&profilerEventHandler=com.xxx.CustomLoggingProfilerEventHandler 

agora, ele está usando o log do slf4j, se seu log padrão for log4j, você deve adicionar as dependencies slf4j-api, slf4j-log4j12 para usar o log do slf4j

passo 2: [escreva o seu registo personalizado]

 package com.xxx; import java.sql.SQLException; import java.util.Properties; import com.mysql.jdbc.Connection; import com.mysql.jdbc.log.Log; public class CustomLoggingProfilerEventHandler implements ProfilerEventHandler { private Log log; public LoggingProfilerEventHandler() { } public void consumeEvent(ProfilerEvent evt) { /** * you can only print the sql as this.log.logInfo(evt.getMessage()) * you can adjust your sql print log level with: DEBUG,INFO * you can also handle the message to meet your requirement */ this.log.logInfo(evt); } public void destroy() { this.log = null; } public void init(Connection conn, Properties props) throws SQLException { this.log = conn.getLog(); } } 

Aqui está o que funcionou para mim, definido abaixo da propriedade no log4j.file:

 log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=TRACE 

Configurações de propriedades do Hibernate:

 hibernate.show_sql=true 

se você estiver usando o uso do hibernate 3.2.xx

 log4j.logger.org.hibernate.SQL=trace 

ao invés de

 log4j.logger.org.hibernate.SQL=debug 

Você pode registrar isso:

 net.sf.hibernate.hql.QueryTranslator 

Exemplo de saída:

 2013-10-31 14:56:19,029 DEBUG [net.sf.hibernate.hql.QueryTranslator] HQL: select noti.id, noti.idmicrosite, noti.fcaducidad, noti.fpublicacion, noti.tipo, noti.imagen, noti.visible, trad.titulo, trad.subtitulo, trad.laurl, trad.urlnom, trad.fuente, trad.texto from org.ibit.rol.sac.micromodel.Noticia noti join noti.traducciones trad where index(trad)='ca' and noti.visible='S' and noti.idmicrosite=985 and noti.tipo=3446 2013-10-31 14:56:19,029 DEBUG [net.sf.hibernate.hql.QueryTranslator] SQL: select noticia0_.NOT_CODI as x0_0_, noticia0_.NOT_MICCOD as x1_0_, noticia0_.NOT_CADUCA as x2_0_, noticia0_.NOT_PUBLIC as x3_0_, noticia0_.NOT_TIPO as x4_0_, noticia0_.NOT_IMAGEN as x5_0_, noticia0_.NOT_VISIB as x6_0_, traduccion1_.NID_TITULO as x7_0_, traduccion1_.NID_SUBTIT as x8_0_, traduccion1_.NID_URL as x9_0_, traduccion1_.NID_URLNOM as x10_0_, traduccion1_.NID_FUENTE as x11_0_, traduccion1_.NID_TEXTO as x12_0_ from GUS_NOTICS noticia0_ inner join GUS_NOTIDI traduccion1_ on noticia0_.NOT_CODI=traduccion1_.NID_NOTCOD where (traduccion1_.NID_CODIDI='ca' )and(noticia0_.NOT_VISIB='S' )and(noticia0_.NOT_MICCOD=985 )and(noticia0_.NOT_TIPO=3446 ) 

Plugin Log4Jdbc seria melhor para sua exigência. Mostra a seguir

 1. Complete SQL query being hit to the db 2. Parameter values being passed to the query 3. Execution time taken by each query 

Consulte o link abaixo para configurar o Log4Jdbc-

 https://code.google.com/p/log4jdbc/ 

O registro funciona, mas não exatamente o que você quer ou eu queria há algum tempo, mas o P6Spy funciona perfeitamente ,

aqui está o tutorial simples para implementar também o tutorial MKYONG para o P6Spy .

para mim funcionou como charme.

  1. Download da biblioteca do P6Spy

Obtenha o “p6spy-install.jar”

  1. Extraia

Extraia o arquivo p6spy-install.jar , procure por p6spy.jar e spy.properties

  1. Adicionar dependência de biblioteca

Adicione o p6spy.jar à sua dependência de biblioteca de projetos

  1. Modifique o arquivo de propriedades P6Spy

Modifique seu arquivo de configuração do database. Você precisa replace seu driver JDBC existente pelo driver P6Spy JDBC – com.p6spy.engine.spy.P6SpyDriver

Original é o driver MySQL JDBC – com.mysql.jdbc.Driver

  false com.mysql.jdbc.Driver password jdbc:mysql://localhost:3306/mkyong root org.hibernate.dialect.MySQLDialect true  

Mudou para o driver P6Spy JDBC – com.p6spy.engine.spy.P6SpyDriver

  false com.p6spy.engine.spy.P6SpyDriver  password jdbc:mysql://localhost:3306/mkyong root org.hibernate.dialect.MySQLDialect true  
  1. Modificar o arquivo de propriedades do P6Spy Modificar o arquivo de propriedades do spy.propertiesspy.properties

Substitua o real driver pelo seu driver JDBC MySQL existente

 realdriver=com.mysql.jdbc.Driver #specifies another driver to use realdriver2= #specifies a third driver to use realdriver3= 

Alterar o local do arquivo de log Altere o local do arquivo de log na propriedade logfile, todas as instruções SQL farão login nesse arquivo.

janelas

 logfile = c:/spy.log 

* nix

 logfile = /srv/log/spy.log 
  1. Copie “spy.properties” para o caminho de class do projeto

Copie “spy.properties” para a pasta raiz do seu projeto, certifique-se de que seu projeto pode localizar “spy.properties”, senão ele solicitará a “spy.properties” não encontrada.

Use o Wireshark ou algo parecido:

Nenhuma das respostas acima mencionadas irá imprimir sql com parâmetros corretamente ou é uma dor. Eu consegui isso usando o WireShark , que captura todos os comandos sql / sendo enviados do aplicativo para o Oracle / Mysql etc com as consultas.

Todas as respostas aqui são úteis, mas se você estiver usando um XML de contexto de aplicativo Spring para configurar sua fábrica de session, definir a variável de nível log4j SQL apenas faz parte do caminho, também é necessário definir a variável hibernate.show_sql no próprio contexto do aplicativo para fazer com que o Hibernate comece a mostrar os valores.

ApplicationContext.xml possui:

   hibernate.jdbc.batch_size=25 ...  hibernate.show_sql=true   

E seu arquivo log4j precisa

 log4j.logger.org.hibernate.SQL=DEBUG 

Em Java:

Transforme sua consulta em TypedQuery se for uma CriteriaQuery (javax.persistence).

Então:

query.unwrap (org.hibernate.Query.class) .getQueryString ();

O Hibernate mostra a consulta e seus valores de parâmetros em linhas diferentes.

Se você estiver usando application.properties no spring boot e você pode usar abaixo o parâmetro realçado em application.properties.

  1. org.hibernate.SQL mostrará as consultas

    logging.level.org.hibernate.SQL = DEBUG

  2. org.hibernate.type mostrará todos os valores dos parâmetros, que serão mapeados com as consultas select, insert e update. logging.level.org.hibernate.type = TRACE

    • org.hibernate.type.EnumType mostrará o valor do parâmetro do tipo enum

      logging.level.org.hibernate.type.EnumType = TRACE

      exemplo ::

       2018-06-14 11:06:28,217 TRACE [main] [EnumType.java : 321] Binding [active] to parameter: [1] 
    • O sql.BasicBinder mostrará o inteiro, varchar, valor do parâmetro do tipo booleano

      logging.level.org.hibernate.type.descriptor.sql.BasicBinder = TRACE

      exemplo ::

      • 2018-06-14 11: 28: 29,750 TRACE [http-nio-9891-exec-2] [BasicBinder.java: 65] parâmetro de binding [1] como [BOOLEAN] – [true]
      • 2018-06-14 11: 28: 29,751 TRACE [http-nio-9891-exec-2] [BasicBinder.java: 65] parâmetro de binding [2] como [INTEGER] – [1]
      • 2018-06-14 11: 28: 29,752 TRACE [http-nio-9891-exec-2] [BasicBinder.java: 65] parâmetro de binding [3] como [VARCHAR] – [public]

A solução mais simples para mim é implementar um stringReplace regular para replace inputs de parâmetros por valores de parâmetros (tratando todos os parâmetros como string, para simplificar):

  String debugedSql = sql; //then, for each named parameter debugedSql = debugedSql.replaceAll(":"+key, "'"+value.toString()+"'"); //and finnaly println(debugedSql); 

ou algo similar para parâmetros posicionais (?).
Cuide dos valores nulos e dos tipos de valores específicos, como date, se você quiser que um sql pronto para execução seja registrado.