¿Cómo ver las consultas SQL emitidas por JPA?


155

Cuando mi código emite una llamada como esta:

entityManager.find(Customer.class, customerID);

¿Cómo puedo ver la consulta SQL para esta llamada? Suponiendo que no tengo acceso al servidor de base de datos para perfilar / monitorear las llamadas, ¿hay alguna forma de registrar o ver dentro de mi IDE las consultas SQL correspondientes emitidas por llamadas JPA? Voy en contra de SQL Server 2008 R2 usando el controlador jTDS.


8
¿Qué es el proveedor de JPA? Creo que esta configuración es específica del proveedor.
btiernay

@Sajee, ¿podría marcar la respuesta de axtavt como aceptada para que dirija a los visitantes a su pregunta directamente a esta respuesta?
8bitjunkie

Respuestas:


332

Las opciones de registro son específicas del proveedor. Necesita saber qué implementación de JPA utiliza.

  • Hibernate ( ver aquí ):

    <property name = "hibernate.show_sql" value = "true" />
  • EclipseLink ( ver aquí ):

    <property name="eclipselink.logging.level" value="FINE"/>
  • OpenJPA ( ver aquí ):

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

    Establezca la categoría de registro DataNucleus.Datastore.Nativea un nivel, como DEBUG.


44
@Sajee: Debería marcar esta respuesta con una marca de verificación para indicar que esta es la respuesta aceptada. Funciona muy bien para mí, usando Hibernate. Si aprueba esta respuesta, usted y el respondedor obtendrán más puntos y más permisos en stackoverflow.com.
LS

57
Pondría esta línea en su persistence.xml para cualquier cuerpo que sea curioso. Estaría debajo del nodo <properties> ... Lo siento si eso es obvio, estaba confundido acerca de dónde ponerlo yo mismo.
SoftwareSavant

55
Al usar Hibernate y log4j, también puede configurar el registrador "org.hibernate.SQL" en DEBUG ( javalobby.org/java/forums/t44119.html )
MosheElisha

Además, parece que el nodo <properties> necesita estar debajo de todo lo demás dentro de <persistence-unit>. <3 XML.
Tom Spurling

1
¿Dónde deben establecerse estas propiedades?
Alex Worden

34

Además, si está utilizando EclipseLink y desea generar los valores de los parámetros SQL, puede agregar esta propiedad a su archivo persistence.xml:

<property name="eclipselink.logging.parameters" value="true"/>

¿Hay alguna alternativa para obtener los valores de enlace en intellij?
Vinícius M

15

Si usa hibernate y logback como su registrador, podría usar lo siguiente (muestra solo los enlaces y no los 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 la consulta

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

org.hibernate.type = TRACE imprime los enlaces y normalmente los resultados, que se suprimirán a través del filtro personalizado

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

Necesita la dependencia de janino (http://logback.qos.ch/manual/filters.html#JaninoEventEvaluator):

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

15

En EclipseLink para obtener el SQL para una consulta específica en tiempo de ejecución, puede usar la 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 contendrá? para los parámetros Para traducir el SQL con los argumentos, necesita un DatabaseRecord con los valores de los parámetros.

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

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

Fuente: Cómo obtener el SQL para una consulta


¿Qué es recordWithValues? ¿Es posible obtenerlo de DatabaseQuery o EJBQueryImpl?
zmeda

1
El argumento Record es uno de (Record, XMLRecord) que contiene los argumentos de la consulta
Tomasz

Si tengo algo como Query myQuery = entityManager.createNamedQuery ("MyEntity.findMe"); myQuery.setParameter ("param1", "someValue); ¿Cómo obtener recordWithValues ​​de myQuery?
zmeda

Actualicé mi respuesta para incluir la creación recordWithValues.
Tomasz

Oye, ¿sabes cómo hacer esto para la basura eclipseLink que no se ejecuta con JPA? (Ni siquiera sé qué es exactamente, pero ha generado clases de mapeo a partir de una aplicación de banco de trabajo ... Sin embargo, no tengo un EM pero solo un servicio toplink, puedo solicitar una sesión, pero no conozco ninguna consulta. use clases como ReadAllQuery, ExpressionBuilder y Expression. No necesita responder si no está claro (no soy un profesional en esto, estoy acostumbrado a JPA), eliminaré este comentario dentro de las próximas 48 horas e intentaré hacer una pregunta más clara;)
JBA

7

Para ver todos los SQL y parámetros en OpenJPA, coloque estos dos parámetros en persistence.xml:

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

5

Si desea ver las consultas exactas con valores de parámetros y valores de retorno, puede usar un controlador proxy jdbc. Interceptará todas las llamadas jdbc y registrará sus valores. Algunos proxies:

  • log4jdbc
  • jdbcspy

También pueden proporcionar algunas características adicionales, como medir el tiempo de ejecución de consultas y recopilar estadísticas.


4

Ejemplo 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>


1
Por favor explique su respuesta un poco más. Supongo que la sección principal es la sección org.hibernate.SQL?
JackDev

2

He hecho una hoja de trucos que creo que puede ser útil para otros. En todos los ejemplos, puede eliminar la format_sqlpropiedad si desea mantener las consultas registradas en una sola línea (sin impresión bonita).

Imprima bastante las consultas SQL para estandarizar sin parámetros de declaraciones preparadas y sin optimizaciones de un marco de registro :

application.properties expediente:

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

application.yml expediente:

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

Imprima consultas SQL con parámetros de declaraciones preparadas utilizando un marco de registro :

application.properties expediente:

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

application.yml expediente:

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

Imprima consultas SQL sin parámetros de declaraciones preparadas utilizando un marco de registro :

application.properties expediente:

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

application.yml expediente:

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

Fuente (y más detalles): https://www.baeldung.com/sql-logging-spring-boot


1

Además, si usa WildFly / JBoss, establezca el nivel de registro de org.hibernate en DEBUG

Hibernate Logging en WildFly


1

Otra buena opción si tiene demasiado registro y desea colocar solo como temporal System.out.println(), puede, según su proveedor:

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());

En nuestra implementación basada en openjpa, esto no muestra los parámetros como parte de la consulta para una consulta parametrizada.
Timwaagh

1

Si está utilizando Spring Framework. Modifique su archivo application.properties como se muestra a continuación

#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  


0

Con Spring Boot simplemente agregue: spring.jpa.show-sql = true a application.properties. Esto mostrará la consulta pero sin los parámetros reales (¿verá? En lugar de cada parámetro).


0

Durante el desarrollo exploratorio, y para enfocar el registro de depuración de SQL en el método específico que quiero verificar, decoro ese método con las siguientes declaraciones de registrador:

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);

0

EclipseLink para generar el SQL (persistence.xml config):

<property name="eclipselink.logging.level.sql" value="FINE" />

-2

Hay un archivo llamado persistence.xml Presione Ctrl + Shift + R y encuéntrelo, luego, hay un lugar escrito como showSQL.

Solo ponlo como cierto

No estoy seguro de si el servidor debe iniciarse como modo de depuración. Verifique los SQL creados en la consola.


esto no es suficiente para mostrar parámetros que solo muestra la instrucción sql? para los parámetros
Ebuzer Taha KANAT

1
"Algo así como showSQL" no es la respuesta. y Ctrl + Shift + R? Has hecho una suposición sobre el IDE.
8bitjunkie
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.