如何查看 JPA 发出的 SQL 查询?

Posted

技术标签:

【中文标题】如何查看 JPA 发出的 SQL 查询?【英文标题】:How to view the SQL queries issued by JPA? 【发布时间】:2011-05-20 18:11:15 【问题描述】:

当我的代码发出这样的调用时:

entityManager.find(Customer.class, customerID);

如何查看此调用的 SQL 查询?假设我无权访问数据库服务器来分析/监视调用,有没有办法在我的 IDE 中记录或查看 JPA 调用发出的相应 SQL 查询?我将使用 jTDS 驱动程序来对抗 SQL Server 2008 R2。

【问题讨论】:

什么是 JPA 提供程序?我相信此设置是特定于提供商的。 @Sajee,您能否将 axtavt 的答案标记为已接受,以便将访问者直接引导至此答案? 【参考方案1】:

有一个名为 persistence.xml 的文件 按Ctrl+Shift+R找到它,然后,有个地方写了showSQL之类的东西。

把它当真

我不确定服务器是否必须以调试模式启动。 检查控制台上创建的 SQL。

【讨论】:

这还不足以显示参数sql语句只显示?用于参数。 “ShowSQL 之类的东西”不是答案。和 Ctrl + Shift + R?您已经对 IDE 做出了假设。【参考方案2】:

见Can't make hibernate stop showing SQL using Spring JPA Vendor Adapter

【讨论】:

我没有使用 Hibernate。 AFAIK,只是普通的旧 JPA。 showSQL 看起来像一个 Hibernate 属性。这对我有用吗? 看起来答案是否定的。我在日志中没有看到任何 SQL。 Sajee,你如何在你的 persistence.xml 中声明属性?【参考方案3】:

日志记录选项是特定于提供商的。您需要知道您使用的是哪种 JPA 实现。

休眠 (see here):

<property name = "hibernate.show_sql" value = "true" />

EclipseLink (see here):

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

OpenJPA (see here):

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

DataNucleus (see here):

将日志类别DataNucleus.Datastore.Native 设置为一个级别,例如DEBUG

【讨论】:

@Sajee:您应该勾选这个答案以表明这是已接受的答案。使用 Hibernate 对我来说非常有用。如果您同意此回答,您和回答者将在 ***.com 上获得更多积分和更多权限。 您可以将此行放在您的 persistence.xml 中,用于任何好奇的主体。它将在 节点下...抱歉,如果这很明显,我只是对自己放置它的位置感到困惑。 在使用Hibernate和log4j时,也可以将“org.hibernate.SQL”logger设置为DEBUG(javalobby.org/java/forums/t44119.html) 此外,似乎 节点需要位于 中的所有其他内容之下。 这些属性应该在哪里设置?【参考方案4】:

另外,如果您正在使用 EclipseLink 并且想要输出 SQL 参数值,您可以将此属性添加到您的 persistence.xml 文件中:

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

【讨论】:

在 intellij 中获取绑定值是否有替代方法?【参考方案5】:

在 EclipseLink 中,要在运行时获取特定查询的 SQL,您可以使用 DatabaseQuery API:

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

来源:How to get the SQL for a Query

【讨论】:

什么是recordWithValues?是否可以从 DatabaseQuery 或 EJBQueryImpl 中获取? Record 参数是包含查询参数的 (Record, XMLRecord) 之一 如果我有类似 Query myQuery = entityManager.createNamedQuery("MyEntity.findMe"); myQuery.setParameter("param1", "someValue); 如何从 myQuery 中获取 recordWithValues? 更新了我的答案以包括 recordWithValues 创建。 嘿,您知道如何为未使用 JPA 运行的 eclipseLink 废话执行此操作吗? (我什至不知道它到底是什么,但它已经从工作台应用程序生成了映射类......但是我没有 EM,但只有一个 toplink 服务我可以请求一个会话,但它不知道任何查询。我使用 ReadAllQuery、ExpressionBuilder 和 Expression 等类。如果它太不清楚,您不需要回复(我不是这方面的专业人士,我已经习惯了 JPA)我将在接下来的 48 小时内删除此评论并尝试提出更清晰的问题;) 【参考方案6】:

如果您使用 hibernate 和 logback 作为您的记录器,您可以使用以下内容(仅显示绑定而不显示结果):

<appender
    name="STDOUT"
    class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%dyyyy-MM-dd HH:mm:ss.SSS [%thread] %-5level %logger36 -
            %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>

【讨论】:

【参考方案7】:

如果您想查看带有参数值和返回值的确切查询,您可以使用 jdbc 代理驱动程序。它将拦截所有 jdbc 调用并记录它们的值。一些代理:

log4jdbc jdbcspy

它们还可能提供一些附加功能,例如测量查询的执行时间和收集统计信息。

【讨论】:

【参考方案8】:

为了查看OpenJPA中的所有SQL和参数,把这两个参数放在persistence.xml中:

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

【讨论】:

【参考方案9】:

使用 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>

【讨论】:

请多解释一下你的答案。我假设主要部分是 org.hibernate.SQL 部分?【参考方案10】:

另外,如果使用 WildFly/JBoss,请将 org.hibernate 的日志记录级别设置为 DEBUG

【讨论】:

【参考方案11】:

另一个good option 如果您有太多日志并且只想将System.out.println() 作为临时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.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 的实现中,这不会将参数显示为参数化查询的查询的一部分。【参考方案12】:

使用 Spring Boot 只需将:spring.jpa.show-sql=true 添加到 application.properties。 这将显示查询但没有实际参数(您将看到 ? 而不是每个参数)。

【讨论】:

【参考方案13】:

如果您使用的是 Spring 框架。如下修改您的 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  

【讨论】:

【参考方案14】:

在探索性开发期间,为了将 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);

【讨论】:

【参考方案15】:

我制作了一份我认为对其他人有用的备忘单。在所有示例中,如果您想将记录的查询保留在一行中(没有漂亮的打印),您可以删除 format_sql 属性。

Pretty print 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

【讨论】:

【参考方案16】:

EclipseLink 输出 SQL(persistence.xml config):

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

【讨论】:

【参考方案17】:

JPA 提供商可以为您设置 - 以防有人不想通过 JPA 属性进行控制

public static JpaProperties properties() 
        final JpaProperties jpaProperties = new JpaProperties();
        jpaProperties.setShowSql(true);

【讨论】:

以上是关于如何查看 JPA 发出的 SQL 查询?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Ruby on Rails 中查看给定 ActiveRecord 查询将生成的 SQL

如何查看oracle服务器上正在执行的SQL语句

如何在 Spring Boot 中查看模式 sql (DDL)?

django 在运行测试时如何查看 sql 查询?

如何查看 Access 中按钮触发的 SQL 查询?

如何获取 JPA 生成的 SQL 查询?