Làm cách nào để xem các truy vấn SQL do JPA ban hành?


155

Khi mã của tôi phát hành một cuộc gọi như thế này:

entityManager.find(Customer.class, customerID);

Làm thế nào tôi có thể thấy truy vấn SQL cho cuộc gọi này? Giả sử tôi không có quyền truy cập vào máy chủ cơ sở dữ liệu để lập hồ sơ / giám sát các cuộc gọi, có cách nào để đăng nhập hoặc xem trong IDE của tôi các truy vấn SQL tương ứng do các cuộc gọi JPA đưa ra không? Tôi đang chống lại SQL Server 2008 R2 bằng trình điều khiển jTDS.


8
Nhà cung cấp JPA là gì? Tôi tin rằng thiết lập này là nhà cung cấp cụ thể.
btiernay

@Sajee xin vui lòng bạn có thể đánh dấu câu trả lời của axtavt là được chấp nhận để nó hướng khách truy cập đến câu hỏi của bạn thẳng đến câu trả lời này?
8bitjunkie

Câu trả lời:


332

Tùy chọn đăng nhập là nhà cung cấp cụ thể. Bạn cần biết bạn thực hiện JPA nào.

  • Ngủ đông ( xem tại đây ):

    <property name = "hibernate.show_sql" value = "true" />
  • EclipseLink ( xem tại đây ):

    <property name="eclipselink.logging.level" value="FINE"/>
  • OpenJPA ( xem tại đây ):

    <property name="openjpa.Log" value="DefaultLevel=WARN,Runtime=INFO,Tool=INFO,SQL=TRACE"/>
  • DataNucleus ( xem tại đây ):

    Đặt danh mục nhật ký DataNucleus.Datastore.Nativeở mức, như DEBUG.


4
@Sajee: Bạn nên đánh dấu câu trả lời này để cho biết đây là câu trả lời được chấp nhận. Nó hoạt động rất tốt cho tôi, sử dụng Hibernate. Nếu bạn chấp nhận câu trả lời này, bạn và người trả lời sẽ nhận được nhiều điểm hơn và nhiều quyền hơn trên stackoverflow.com.
LS

57
Bạn sẽ đặt dòng này trong tệp kiên trì của bạn cho bất kỳ cơ quan nào có tính tò mò. Nó sẽ nằm dưới nút <property> ... Xin lỗi nếu điều đó là hiển nhiên, tôi chỉ bối rối về việc tự đặt nó ở đâu.
SoftwareSavant

5
Khi sử dụng Hibernate và log4j, bạn cũng có thể đặt trình ghi nhật ký "org.hibernate.SQL" thành DEBUG ( javalulk.org/java/forums/t44119.html )
MosheElisha

Ngoài ra, có vẻ như nút <property> cần nằm bên dưới mọi thứ khác trong <đơn vị kiên trì>. <3 XML.
Tom Spurling

1
Những thuộc tính này nên được đặt ở đâu?
Alex Worden

34

Ngoài ra, nếu bạn đang sử dụng EclipseLink và muốn xuất các giá trị tham số SQL, bạn có thể thêm thuộc tính này vào tệp tệp Persence.xml của mình:

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

Có một sự thay thế để có được các giá trị ràng buộc trong intellij?
Vinícius M

15

Nếu bạn sử dụng hibernate và logback làm logger, bạn có thể sử dụng các mục sau (chỉ hiển thị các ràng buộc chứ không hiển thị kết quả):

<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 in Truy vấn

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

org.hibernate.type = TRACE in các liên kết và thông thường các kết quả sẽ bị loại bỏ thông qua bộ lọc tùy chỉnh

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

Bạn cần phụ thuộc 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

Trong EclipseLink để nhận SQL cho một Truy vấn cụ thể khi chạy, bạn có thể sử dụng 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 này sẽ chứa? cho các tham số. Để có được SQL dịch với các đối số, bạn cần một DatabaseRecord với các giá trị tham số.

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

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

Nguồn: Cách nhận SQL cho truy vấn


RecordWithValues ​​là gì? Có thể lấy nó từ DatabaseQuery hoặc EJBQueryImpl không?
zmeda

1
Đối số Bản ghi là một trong (Bản ghi, XMLRecord) có chứa các đối số truy vấn
Tomasz

Nếu tôi có một cái gì đó như Truy vấn myQuery = entityManager.createNamedQuery ("MyEntity.findMe"); myQuery.setParameter ("param1", "someValue); Làm cách nào để lấy recordWithValues ​​từ myQuery?
zmeda

Cập nhật câu trả lời của tôi để bao gồm tạo recordWithValues.
Tomasz

Này, bạn có biết làm thế nào để làm điều này cho crap eclipseLink không chạy với JPA không? (Tôi thậm chí không biết chính xác nó là gì nhưng nó đã tạo ra các lớp ánh xạ từ một ứng dụng bàn làm việc .... Tuy nhiên tôi không có EM mà chỉ có Dịch vụ toplink tôi có thể yêu cầu Phiên nhưng không biết về bất kỳ truy vấn nào. Tôi không biết sử dụng các lớp như ReadAllQuery, ExpressionBuilder và Expression. Bạn không cần trả lời nếu nó không rõ ràng (tôi không phải là người chuyên nghiệp trong việc này, tôi đã sử dụng JPA) tôi sẽ xóa nhận xét này trong vòng 48 giờ tới và cố gắng hỏi một câu hỏi rõ ràng hơn;)
JBA

7

Để xem tất cả SQL và các tham số trong OpenJPA, hãy đặt hai tham số này vào tệp Persence.xml:

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

5

Nếu bạn muốn xem các truy vấn chính xác hoàn toàn với các giá trị tham số và trả về giá trị, bạn có thể sử dụng trình điều khiển proxy jdbc. Nó sẽ chặn tất cả các cuộc gọi jdbc và ghi lại giá trị của chúng. Một số proxy:

  • log4jdbc
  • jdbcspy

Họ cũng có thể cung cấp một số tính năng bổ sung, như đo thời gian thực hiện cho các truy vấn và thu thập số liệu thống kê.


4

Ví dụ sử dụng 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
Hãy giải thích câu trả lời của bạn nhiều hơn một chút. Tôi giả sử phần chính là phần org.hibernate.SQL?
JackDev

1

Ngoài ra, nếu sử dụng WildFly / JBoss, hãy đặt mức ghi nhật ký của org.hibernate thành DEBUG

Đăng nhập ngủ đông trong WildFly


1

Một tùy chọn tốt khác nếu bạn có quá nhiều nhật ký và bạn chỉ muốn đặt dưới dạng tạm thời System.out.println(), bạn có thể, tùy thuộc vào nhà cung cấp của bạn làm:

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

Trong triển khai dựa trên openjpa của chúng tôi, điều này không hiển thị các tham số như là một phần của truy vấn cho truy vấn tham số.
timwaagh

1

Nếu bạn đang sử dụng Spring framework. Sửa đổi tệp application.properIES của bạn như dưới đây

#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  

1

Tôi đã tạo ra một mánh gian lận mà tôi nghĩ có thể hữu ích cho người khác. Trong tất cả các ví dụ, bạn có thể loại bỏformat_sql tính nếu bạn muốn giữ các truy vấn đã ghi trên một dòng (không in đẹp).

Các truy vấn SQL được in ra chuẩn để không có tham số của các câu lệnh được chuẩn bị và không tối ưu hóa khung đăng nhập :

application.properties tập tin:

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

application.yml tập tin:

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

Các truy vấn SQL in đẹp với các tham số của các câu lệnh được chuẩn bị bằng cách sử dụng khung ghi nhật ký :

application.properties tập tin:

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

application.yml tập tin:

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

Các truy vấn SQL in đẹp mà không có tham số của các câu lệnh được chuẩn bị bằng cách sử dụng khung ghi nhật ký :

application.properties tập tin:

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

application.yml tập tin:

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

Nguồn (và biết thêm chi tiết): https://www.baeldung.com/sql-logging-spring-boot


0

Tôi không sử dụng Hibernate. AFAIK, chỉ đơn giản là JPA cũ. showQuery trông giống như một tài sản Hibernate. Điều đó sẽ làm việc trong trường hợp của tôi?
Sajee

Có vẻ như câu trả lời là Không. Tôi không thấy bất kỳ SQL nào trong nhật ký.
Sajee

1
Sajee, làm thế nào để bạn khai báo các thuộc tính trên tệp Persence.xml của bạn?
Gondim

0

Với Spring Boot, chỉ cần thêm: spring.jpa.show-sql = true vào application.properIES. Điều này sẽ hiển thị truy vấn nhưng không có các tham số thực tế (bạn sẽ thấy? Thay vì từng tham số).


0

Trong quá trình phát triển khám phá và để tập trung ghi nhật ký gỡ lỗi SQL vào phương thức cụ thể mà tôi muốn kiểm tra, tôi trang trí phương thức đó bằng các câu lệnh logger sau:

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 để xuất SQL (cấu hình bền vững):

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

-2

Có một tệp có tên là bền vững Nhấn Ctrl + Shift + R và tìm thấy nó, sau đó, có một nơi được viết giống như showQuery.

Cứ nói như thật

Tôi không chắc máy chủ có phải được khởi động ở chế độ Gỡ lỗi không. Kiểm tra các SQL được tạo trên bàn điều khiển.


Điều này là không đủ để hiển thị tham số sql tuyên bố chỉ hiển thị? cho các tham số.
Ebuzer Taha KANAT

1
"Một cái gì đó giống như showQuery" không trả lời. và Ctrl + Shift + R? Bạn đã đưa ra một giả định về IDE.
8bitjunkie
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.