Як переглянути SQL запити, видані JPA?


155

Коли мій код видає такий дзвінок:

entityManager.find(Customer.class, customerID);

Як я бачу SQL-запит для цього дзвінка? Якщо припустити, що я не маю доступу до сервера баз даних для профілювання / моніторингу викликів, чи є спосіб увімкнути або переглянути в межах моєї IDE відповідні запити SQL, що видаються дзвінками JPA? Я збираюся проти SQL Server 2008 R2 за допомогою драйвера jTDS.


8
Що таке постачальник JPA? Я вважаю, що цей параметр залежить від постачальника.
btiernay

@Sajee, будь ласка, чи можете ви позначити відповідь axtavt як прийняту, щоб вона спрямовувала відвідувачів на ваше запитання прямо до цієї відповіді?
8bitjunkie

Відповіді:


332

Параметри журналу залежать від постачальника. Вам потрібно знати, яку реалізацію JPA ви використовуєте.

  • Зимує ( див. Тут ):

    <property name = "hibernate.show_sql" value = "true" />
  • EclipseLink ( див. Тут ):

    <property name="eclipselink.logging.level" value="FINE"/>
  • OpenJPA ( див. Тут ):

    <property name="openjpa.Log" value="DefaultLevel=WARN,Runtime=INFO,Tool=INFO,SQL=TRACE"/>
  • DataNucleus ( див. Тут ):

    Установіть категорію журналу DataNucleus.Datastore.Nativeна рівні, наприклад DEBUG.


4
@Sajee: Ви повинні дати цю відповідь галочкою, щоб вказати, що це прийнята відповідь. Для мене це чудово працює, використовуючи сплячку. Якщо ви схвалюєте цю відповідь, ви та відповідач отримаєте більше балів та більше дозволів на сайті stackoverflow.com.
LS

57
Ви б поставили цю лінію у вашій persistent.xml для будь-якого цікавого органу. Це було б під вузлом <властивості> Вибачте, якщо це очевидно, я просто розгубився, куди його самому поставити.
SoftwareSavant

5
Використовуючи Hibernate та log4j, ви також можете встановити реєстратор "org.hibernate.SQL" на DEBUG ( javalobby.org/java/forums/t44119.html )
MosheElisha

Крім того, здається, що вузол <properties> повинен знаходитись під усім іншим в <persistent-unit>. <3 XML
Том Спарлінг

1
Де слід встановити ці властивості?
Алекс Worden

34

Крім того, якщо ви використовуєте EclipseLink і хочете вивести значення параметрів SQL, ви можете додати це властивість до вашого файла persistent.xml:

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

Чи існує альтернатива отримати значення прив'язки в Intellij?
Vinícius M

15

Якщо ви використовуєте сплячий режим і зворотний зв'язок в якості реєстратора, ви можете використовувати наступне (показує лише прив'язки, а не результати):

<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 друкує Запит

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

org.hibernate.type = TRACE друкує прив'язки і зазвичай результати, які будуть придушені через спеціальний фільтр

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

Вам потрібна 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

У EclipseLink, щоб отримати SQL для конкретного запиту під час виконання, ви можете використовувати 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();

Цей SQL буде містити? для параметрів. Щоб перевести SQL з аргументами, вам потрібен DatabaseRecord зі значеннями параметра.

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

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

Джерело: Як отримати SQL для запиту


Що таке записWithValues? Чи можна отримати його з DatabaseQuery або EJBQueryImpl?
zmeda

1
Аргумент Record - один із (Record, XMLRecord), який містить аргументи запиту
Tomasz

Якщо у мене є щось на кшталт Query myQuery = entitManager.createNamedQuery ("MyEntity.findMe"); myQuery.setParameter ("param1", "someValue); Як отримати записWithValues ​​з myQuery?"
zmeda

Оновлено мою відповідь, щоб включити створення RecordWithValues.
Томаш

Гей, чи знаєте ви, як це зробити для eclipseLink лайно, яке не працює з JPA? (Я навіть не знаю, що саме це, але це створило картографічні класи з додатку робочої версії .... Однак у мене немає ЕМ, але лише сервіс верхнього зв’язку, я можу запитати сесію, але це не знає жодного запиту. Я використовуйте такі класи, як ReadAllQuery, ExpressionBuilder та Expression. Вам не потрібно відповідати, якщо це занадто незрозуміло (я не є профі в цьому, я звик до JPA), я видаляю цей коментар протягом наступних 48 годин і спробую задати більш чітке запитання;)
JBA

7

Для того, щоб переглянути всі SQL та параметри у OpenJPA, помістіть ці два параметри у persistent.xml:

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

5

Якщо ви хочете побачити точні запити взагалі зі значеннями параметрів і значеннями повернення, ви можете використовувати проксі-драйвер jdbc. Він перехопить усі дзвінки jdbc і запише їх значення. Деякі проксі

  • log4jdbc
  • jdbcspy

Вони також можуть надавати деякі додаткові функції, такі як вимірювання часу виконання запитів та збирання статистики.


4

Приклад використання 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
Будь ласка, поясніть свою відповідь трохи більше. Я припускаю, що основним розділом є розділ org.hibernate.SQL?
JackDev

2

Я зробив шпаргалку, на яку я думаю, може бути корисною для інших. У всіх прикладах ви можете видалити format_sqlвластивість, якщо ви хочете, щоб увійшли запити, що входять у систему, на одному рядку (не дуже друкованого).

Досить друкувати SQL-запити, щоб вирівняти без параметрів підготовлених операторів та без оптимізацій структури журналу :

application.properties файл:

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

application.yml файл:

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

Досить друкувати SQL запити з параметрами підготовлених операторів за допомогою системи реєстрації журналів :

application.properties файл:

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

application.yml файл:

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

Симпатичний друк SQL запитів без параметрів підготовлених операторів за допомогою системи реєстрації даних :

application.properties файл:

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

application.yml файл:

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

Джерело (та більше деталей): https://www.baeldung.com/sql-logging-spring-boot


1

Крім того, якщо використовується WildFly / JBoss, встановіть рівень реєстрації org.hibernate на DEBUG

Перебуває в сплячому режимі в WildFly


1

Ще один хороший варіант, якщо у вас занадто багато журналу і ви хочете розмістити лише як часовий System.out.println(), ви можете, в залежності від вашого оператора:

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

У нашій реалізації openjpa це не відображає параметри як частина запиту для параметризованого запиту.
timwaagh

1

Якщо ви використовуєте Spring Framework. Змініть файл application.properties, як показано нижче

#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

Я не використовую сплячку. AFAIK, просто звичайний старий JPA. showSQL виглядає як властивість Hibernate. Чи спрацює це в моєму випадку?
Sajee

Схоже, відповідь - Ні. Я не бачу жодного SQL в журналах.
Sajee

1
Sajee, як ти декларуєш властивості на своїй persistent.xml?
Гондім

0

За допомогою Spring Boot просто додайте: spring.jpa.show-sql = вірно в application.properties. Це покаже запит, але без фактичних параметрів (ви побачите? Замість кожного параметра).


0

Під час дослідницької розробки та для того, щоб зосередити журнал налагодження SQL на конкретному методі, який я хочу перевірити, я прикрашаю цей метод такими твердженнями реєстратора:

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 для виведення SQL (persistent.xml config):

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

-2

Існує файл під назвою persistent.xml Натисніть Ctrl + Shift + R і знайдіть його, значить, є місце, написане щось на зразок showSQL.

Просто поставте це як правду

Я не впевнений, чи потрібно запускати сервер у режимі налагодження. Перевірте створені на консолі SQL.


цього недостатньо, щоб параметри показано лише показання sql? для параметрів.
Ebuzer Taha KANAT

1
"Щось на зразок showSQL" - це не відповідь. і Ctrl + Shift + R? Ви зробили припущення щодо IDE.
8bitjunkie
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.