Como visualizar as consultas SQL emitidas pela JPA?

155

Quando meu código emite uma chamada como esta:

entityManager.find(Customer.class, customerID);

Como posso ver a consulta SQL para esta chamada? Supondo que não tenho acesso ao servidor de banco de dados para criar um perfil / monitorar as chamadas, existe uma maneira de registrar ou exibir no meu IDE as consultas SQL correspondentes emitidas pelas chamadas JPA? Estou indo contra o SQL Server 2008 R2 usando o driver jTDS.

Sajee
fonte
8
O que é o provedor JPA? Acredito que essa configuração seja específica do provedor.
btiernay 6/12/10
@ Sarajee, por favor, você poderia marcar a resposta de axtavt como aceita, para que direcione os visitantes para sua pergunta diretamente para essa resposta?
8bjunkie

Respostas:

332

As opções de log são específicas do provedor. Você precisa saber qual implementação de JPA você usa.

  • Hibernação ( veja aqui ):

    <property name = "hibernate.show_sql" value = "true" />
  • EclipseLink ( veja aqui ):

    <property name="eclipselink.logging.level" value="FINE"/>
  • OpenJPA ( veja aqui ):

    <property name="openjpa.Log" value="DefaultLevel=WARN,Runtime=INFO,Tool=INFO,SQL=TRACE"/>
  • DataNucleus ( veja aqui ):

    Defina a categoria de log DataNucleus.Datastore.Nativepara um nível, como DEBUG.

axtavt
fonte
4
@ Sarah: Você deve dar uma resposta a esta resposta para indicar que esta é a resposta aceita. Funciona muito bem para mim, usando o Hibernate. Se você aprovar esta resposta, você e o atendente receberão mais pontos e mais permissões no stackoverflow.com.
LS
57
Você colocaria essa linha no seu persistence.xml para qualquer corpo que seja exigente. Estaria sob o nó <properties> ... Desculpe, se isso é óbvio, fiquei confuso sobre onde colocá-lo.
SoftwareSavant
5
Ao usar o Hibernate e log4j, você também pode definir o logger "org.hibernate.SQL" para depurar ( javalobby.org/java/forums/t44119.html )
MosheElisha
Além disso, parece que o nó <properties> precisa estar abaixo de tudo o mais dentro da <persistence-unit>. <3 XML.
Tom Spurling
1
Onde essas propriedades devem ser definidas?
Alex Worden
34

Além disso, se você estiver usando o EclipseLink e quiser gerar os valores dos parâmetros SQL, poderá adicionar esta propriedade ao seu arquivo persistence.xml:

<property name="eclipselink.logging.parameters" value="true"/>
ThePizzle
fonte
Existe uma alternativa para obter os valores vinculativos no intellij?
Vinícius M
15

Se você usar o hibernate e o logback como seu criador de logs, poderá usar o seguinte (mostra apenas as ligações e não os resultados):

<appender
    name="STDOUT"
    class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} -
            %msg%n</pattern>
    </encoder>
    <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
        <evaluator>
            <expression>return message.toLowerCase().contains("org.hibernate.type") &amp;&amp;
                logger.startsWith("returning");</expression>
        </evaluator>
        <OnMismatch>NEUTRAL</OnMismatch>
        <OnMatch>DENY</OnMatch>
    </filter>
</appender>

org.hibernate.SQL = DEBUG imprime a consulta

<logger name="org.hibernate.SQL">
    <level value="DEBUG" />
</logger>

org.hibernate.type = TRACE imprime as ligações e normalmente os resultados, que serão suprimidos pelo filtro personalizado

<logger name="org.hibernate.type">
    <level value="TRACE" />
</logger>

Você precisa da dependência do janino (http://logback.qos.ch/manual/filters.html#JaninoEventEvaluator):

<dependency>
    <groupId>org.codehaus.janino</groupId>
    <artifactId>janino</artifactId>
    <version>2.6.1</version>
</dependency>
Kuhpid
fonte
15

No EclipseLink para obter o SQL para uma consulta específica em tempo de execução, você pode usar a API DatabaseQuery:

Query query = em.createNamedQuery("findMe"); 
Session session = em.unwrap(JpaEntityManager.class).getActiveSession(); 
DatabaseQuery databaseQuery = ((EJBQueryImpl)query).getDatabaseQuery(); 
databaseQuery.prepareCall(session, new DatabaseRecord());

String sqlString = databaseQuery.getSQLString();

Este SQL irá conter? para parâmetros. Para obter o SQL traduzido com os argumentos, você precisa de um DatabaseRecord com os valores dos parâmetros.

DatabaseRecord recordWithValues= new DatabaseRecord();
recordWithValues.add(new DatabaseField("param1"), "someValue");

String sqlStringWithArgs = 
         databaseQuery.getTranslatedSQLString(session, recordWithValues);

Fonte: Como obter o SQL para uma consulta

Tomasz
fonte
O que é recordWithValues? É possível obtê-lo no DatabaseQuery ou no EJBQueryImpl?
zmeda
1
O argumento Record é um dos (Record, XMLRecord) que contém os argumentos da consulta
Tomasz
Se eu tiver algo como Query myQuery = entityManager.createNamedQuery ("MyEntity.findMe"); myQuery.setParameter ("param1", "someValue); Como obter recordWithValues ​​a partir de myQuery?"
zmeda
Atualizei minha resposta para incluir a criação recordWithValues.
Tomasz
Ei, você sabe como fazer isso para a porcaria do eclipseLink que não está sendo executada com o JPA? (Eu nem sei exatamente o que é, mas ele gerou classes de mapeamento a partir de um aplicativo do ambiente de trabalho .... No entanto, eu não tenho um EM, mas apenas um serviço de toplink, posso solicitar uma sessão, mas que não conhece nenhuma consulta. use Classes como ReadAllQuery, ExpressionBuilder e Expression. Você não precisa responder se não estiver claro (não sou profissional nisso, estou acostumado ao JPA). Excluirei esse comentário nas próximas 48 horas e tentarei fazer uma pergunta mais clara;)
JB #
7

Para visualizar todo o SQL e parâmetros no OpenJPA, coloque esses dois parâmetros no persistence.xml:

<property name="openjpa.Log" value="DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=TRACE"/>
<property name="openjpa.ConnectionFactoryProperties" value="PrintParameters=true" />
jfcorugedo
fonte
5

Se você quiser ver as consultas exatas com os valores dos parâmetros e valores de retorno, poderá usar um driver proxy jdbc. Ele interceptará todas as chamadas jdbc e registrará seus valores. Alguns proxies:

  • log4jdbc
  • jdbcspy

Eles também podem fornecer alguns recursos adicionais, como medir o tempo de execução para consultas e coletar estatísticas.

mateusz.fiolka
fonte
4

Exemplo usando log4j ( src \ log4j.xml ):

<?xml version="1.0" encoding="UTF-8" ?>

<appender name="CA" class="org.apache.log4j.AsyncAppender">
    <param name="BufferSize" value="512"/>
    <appender-ref ref="CA_OUTPUT"/>
</appender>
<appender name="CA_OUTPUT" class="org.apache.log4j.ConsoleAppender">
    <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="[%p] %d %c %M - %m%n"/>
    </layout>
</appender>

<logger name="org.hibernate.SQL" additivity="false">
    <level value="DEBUG"/>
    <appender-ref ref="CA"/>
</logger>

<root>
    <level value="WARN"/>
    <appender-ref ref="CA"/>
</root>

Marcus Becker
fonte
1
Por favor, explique sua resposta um pouco mais. Presumo que a seção principal seja a seção org.hibernate.SQL?
precisa saber é o seguinte
2

Fiz uma folha de dicas que acho que pode ser útil para outras pessoas. Em todos os exemplos, você pode remover a format_sqlpropriedade se desejar manter as consultas registradas em uma única linha (nenhuma impressão bonita).

Impressões SQL de impressão bonita para padronizar sem parâmetros de instruções preparadas e sem otimizações de uma estrutura de log :

application.properties Arquivo:

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

application.yml Arquivo:

spring:
  jpa:
    show-sql: true
    properties:
      hibernate:
        format_sql: true

Imprima consultas SQL com parâmetros de instruções preparadas usando uma estrutura de log :

application.properties Arquivo:

spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

application.yml Arquivo:

spring:
  jpa:
    properties:
      hibernate:
        format_sql: true
logging:
  level:
    org:
      hibernate:
        SQL: DEBUG
        type:
          descriptor:
            sql:
              BasicBinder: TRACE

Imprima consultas SQL sem parâmetros de instruções preparadas usando uma estrutura de log :

application.properties Arquivo:

spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.SQL=DEBUG

application.yml Arquivo:

spring:
  jpa:
    properties:
      hibernate:
        format_sql: true
logging:
  level:
    org:
      hibernate:
        SQL: DEBUG

Fonte (e mais detalhes): https://www.baeldung.com/sql-logging-spring-boot

Kent Munthe Caspersen
fonte
1

Além disso, se você estiver usando o WildFly / JBoss, defina o nível de log do org.hibernate como DEBUG

Log do Hibernate no WildFly

Αλέκος
fonte
1

Outra boa opção se você tiver muito log e quiser colocar apenas como temporal System.out.println(), pode, dependendo do seu provedor:

CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<ExaminationType> criteriaQuery = criteriaBuilder.createQuery(getEntityClass()); 

/* For Hibernate */
System.out.println(getEntityManager().createQuery(criteriaQuery).unwrap(org.hibernate.Query.class).getQueryString());

/* For OpenJPA */ 
System.out.println(getEntityManager().createQuery(criteriaQuery).unwrap(org.apache.openjpa.persistence.QueryImpl.class).getQueryString());

/* For EclipseLink */
System.out.println(getEntityManager().createQuery(criteriaQuery).unwrap(JpaQuery.class).getSQLString());
King Midas
fonte
Em nossa implementação baseada em openjpa, isso não mostra os parâmetros como parte da consulta para uma consulta parametrizada.
timwaagh
1

Se você estiver usando o framework Spring. Modifique seu arquivo application.properties como abaixo

#Logging JPA Queries, 1st line Log Query. 2nd line Log parameters of prepared statements 
logging.level.org.hibernate.SQL=DEBUG  
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE  

#Logging JdbcTemplate Queries, 1st line Log Query. 2nd line Log parameters of prepared statements 
logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG  
logging.level.org.springframework.jdbc.core.StatementCreatorUtils=TRACE  
thyzz
fonte
0

Com o Spring Boot, basta adicionar: spring.jpa.show-sql = true a application.properties. Isso mostrará a consulta, mas sem os parâmetros reais (você verá? Em vez de cada parâmetro).

Elhanan Mishraky
fonte
0

Durante o desenvolvimento exploratório, e para focar o log de depuração SQL no método específico que desejo verificar, decorei esse método com as seguintes instruções do logger:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;

((ch.qos.logback.classic.Logger) LoggerFactory.getLogger("org.hibernate.SQL")).setLevel(Level.DEBUG);
entityManager.find(Customer.class, customerID);
((ch.qos.logback.classic.Logger) LoggerFactory.getLogger("org.hibernate.SQL")).setLevel(Level.INFO);
Abdull
fonte
0

EclipseLink para gerar o SQL (persistence.xml config):

<property name="eclipselink.logging.level.sql" value="FINE" />
CamelTM
fonte
-2

Há um arquivo chamado persistence.xml Pressione Ctrl + Shift + R e localize-o; então, há um lugar escrito como showSQL.

Basta colocar como verdade

Não tenho certeza se o servidor deve ser iniciado como modo de depuração. Verifique os SQLs criados no console.

Gondim
fonte
isso não é suficiente para mostrar os parâmetros que a instrução sql mostra apenas? para parâmetros.
Ebuzer Taha KANAT
1
"Algo como showSQL" não é resposta. e Ctrl + Shift + R? Você fez uma suposição sobre o IDE.
8bitjunkie