Bagaimana cara melihat query SQL yang dikeluarkan oleh JPA?


155

Ketika kode saya mengeluarkan panggilan seperti ini:

entityManager.find(Customer.class, customerID);

Bagaimana saya bisa melihat permintaan SQL untuk panggilan ini? Dengan asumsi saya tidak memiliki akses ke server database untuk profil / memonitor panggilan, apakah ada cara untuk login atau melihat dalam IDE saya pertanyaan SQL yang sesuai yang dikeluarkan oleh panggilan JPA? Saya akan menentang SQL Server 2008 R2 menggunakan driver jTDS.


8
Apa penyedia JPA? Saya yakin pengaturan ini khusus untuk penyedia.
btiernay

@Sajee tolong bisakah Anda menandai jawaban axtavt sebagai diterima sehingga mengarahkan pengunjung ke pertanyaan Anda langsung ke jawaban ini?
8bitjunkie

Jawaban:


332

Opsi pencatatan khusus untuk penyedia. Anda perlu tahu implementasi JPA mana yang Anda gunakan.

  • Hibernate ( lihat di sini ):

    <property name = "hibernate.show_sql" value = "true" />
  • EclipseLink ( lihat di sini ):

    <property name="eclipselink.logging.level" value="FINE"/>
  • OpenJPA ( lihat di sini ):

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

    Setel kategori log DataNucleus.Datastore.Nativeke level, seperti DEBUG.


4
@Sajee: Anda harus memberi jawaban ini tanda centang untuk menunjukkan bahwa ini adalah jawaban yang diterima. Ini bekerja bagus untuk saya, menggunakan Hibernate. Jika Anda menyetujui jawaban ini, Anda dan penjawab akan mendapatkan lebih banyak poin dan lebih banyak izin di stackoverflow.com.
LS

57
Anda akan meletakkan baris ini dalam persistence.xml Anda untuk semua tubuh yang currious. Itu akan berada di bawah simpul <properties> ... Maaf jika itu jelas, saya hanya bingung di mana harus meletakkannya sendiri.
SoftwareSavant

5
Saat menggunakan Hibernate dan log4j, Anda juga dapat mengatur logger "org.hibernate.SQL" ke DEBUG ( javalobby.org/java/forums/t44119.html )
MosheElisha

Selain itu, tampaknya simpul <properties> harus berada di bawah yang lainnya di dalam <persistence-unit>. <3 XML.
Tom Spurling

1
Di mana seharusnya properti ini diatur?
Alex Worden

34

Juga, jika Anda menggunakan EclipseLink dan ingin menampilkan nilai parameter SQL, Anda bisa menambahkan properti ini ke file persistence.xml Anda:

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

Apakah ada alternatif untuk mendapatkan nilai pengikatan di intellij?
Vinícius M

15

Jika Anda menggunakan hibernate dan logback sebagai logger Anda, Anda bisa menggunakan yang berikut (hanya menunjukkan binding dan bukan hasilnya):

<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 mencetak Kueri

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

org.hibernate.type = TRACE mencetak binding dan biasanya hasilnya, yang akan ditekan melalui filter khusus

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

Anda memerlukan dependensi 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

Di EclipseLink untuk mendapatkan SQL untuk Permintaan tertentu saat runtime Anda dapat menggunakan 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 ini akan berisi? untuk parameter. Untuk mendapatkan SQL yang diterjemahkan dengan argumen Anda memerlukan DatabaseRecord dengan nilai parameter.

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

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

Sumber: Cara mendapatkan SQL untuk Kueri


Apa itu recordWithValues? Apakah mungkin untuk mendapatkannya dari DatabaseQuery atau EJBQueryImpl?
zmeda

1
Argumen Rekam adalah salah satu dari (Rekam, XMLRecord) yang berisi argumen kueri
Tomasz

Jika saya memiliki sesuatu seperti Query myQuery = entityManager.createNamedQuery ("MyEntity.findMe"); myQuery.setParameter ("param1", "someValue); Bagaimana cara mendapatkan recordWithValues ​​dari myQuery?
zmeda

Memperbarui jawaban saya untuk memasukkan rekaman recordWithValues.
Tomasz

Hai, apakah Anda tahu cara melakukan ini untuk omong kosong eclipseLink yang tidak berjalan dengan JPA? (Saya bahkan tidak tahu apa sebenarnya itu tetapi telah menghasilkan pemetaan-kelas dari aplikasi meja kerja .... Namun saya tidak memiliki EM tetapi hanya layanan toplink saya dapat meminta Sesi tetapi yang tidak tahu pertanyaan apa pun. Saya gunakan Kelas seperti ReadAllQuery, ExpressionBuilder dan Expression. Anda tidak perlu membalas jika terlalu tidak jelas (saya bukan pro dalam hal ini, saya terbiasa dengan JPA) saya akan menghapus komentar ini dalam 48 jam ke depan dan mencoba untuk mengajukan pertanyaan yang lebih jelas;)
JBA

7

Untuk melihat semua SQL dan parameter di OpenJPA, masukkan dua parameter ini di persistence.xml:

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

5

Jika Anda ingin melihat kueri yang tepat sama sekali dengan nilai parameter dan nilai balik Anda dapat menggunakan driver proxy jdbc. Ini akan mencegat semua panggilan jdbc dan mencatat nilainya. Beberapa proxy:

  • log4jdbc
  • jdbcspy

Mereka juga dapat menyediakan beberapa fitur tambahan, seperti mengukur waktu eksekusi untuk pertanyaan dan mengumpulkan statistik.


4

Contoh menggunakan 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
Tolong jelaskan jawaban Anda sedikit lagi. Saya menganggap bagian utama adalah bagian org.hibernate.SQL?
JackDev

2

Saya sudah membuat cheat-sheet yang menurut saya bisa bermanfaat bagi orang lain. Dalam semua contoh, Anda dapat menghapus format_sqlproperti jika Anda ingin menjaga kueri yang dicatat dalam satu baris (tidak ada pencetakan cantik).

Cukup cetak kueri SQL hingga keluar standar tanpa parameter pernyataan yang disiapkan dan tanpa optimisasi kerangka logging :

application.properties mengajukan:

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

application.yml mengajukan:

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

Cukup cetak kueri SQL dengan parameter pernyataan yang disiapkan menggunakan kerangka logging :

application.properties mengajukan:

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

application.yml mengajukan:

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

Cukup cetak kueri SQL tanpa parameter pernyataan yang disiapkan menggunakan kerangka logging :

application.properties mengajukan:

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

application.yml mengajukan:

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

Sumber (dan lebih detail): https://www.baeldung.com/sql-logging-spring-boot


1

Selain itu, jika menggunakan WildFly / JBoss, atur level logging dari org.hibernate ke DEBUG

Hibernate Logging di WildFly


1

Pilihan lain yang bagus jika Anda memiliki terlalu banyak log dan Anda hanya ingin menempatkan sementara System.out.println(), Anda bisa, tergantung pada penyedia Anda lakukan:

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

Dalam implementasi berbasis openjpa kami, ini tidak menunjukkan parameter sebagai bagian dari permintaan untuk permintaan parametrized.
timwaagh

1

Jika Anda menggunakan kerangka kerja Spring. Ubah file application.properties Anda seperti di bawah ini

#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

Dengan Spring Boot cukup tambahkan: spring.jpa.show-sql = true ke application.properties. Ini akan menampilkan kueri tetapi tanpa parameter aktual (Anda akan melihat? Bukannya setiap parameter).


0

Selama pengembangan eksploratif, dan untuk memfokuskan log debugging SQL pada metode spesifik yang ingin saya periksa, saya menghias metode itu dengan pernyataan logger berikut:

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 untuk menampilkan SQL (persistence.xml config):

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

-2

Ada file bernama persistence.xml Tekan Ctrl + Shift + R dan temukan, lalu, ada tempat menulis sesuatu seperti showSQL.

Sederhananya

Saya tidak yakin apakah server harus dimulai sebagai mode Debug. Periksa SQL yang dibuat di konsol.


ini tidak cukup untuk menunjukkan parameter hanya menunjukkan pernyataan sql? untuk parameter.
Ebuzer Taha KANAT

1
"Sesuatu seperti showSQL" bukan jawaban. dan Ctrl + Shift + R? Anda telah membuat asumsi tentang IDE.
8bitjunkie
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.