在 Spring Boot 中显示 Hibernate/JPA 的 SQL 语句

更新于 2025-12-30

baeldung 2018-04-09

1. 概述

Spring JDBC 和 JPA 对原生 JDBC API 提供了抽象层,使开发者无需编写原生 SQL 查询。然而,在调试时,我们经常需要查看这些自动生成的 SQL 查询及其执行顺序。

在本篇快速教程中,我们将探讨在 Spring Boot 中记录这些 SQL 查询的多种方法。

2. 记录 JPA 查询

2.1. 输出到标准输出(Standard Output)

最简单的方式是将以下配置添加到 application.properties 文件中,将 SQL 查询直接打印到标准输出:

spring.jpa.show-sql=true

若希望美化(格式化)SQL 输出,可以再添加:

spring.jpa.properties.hibernate.format_sql=true

配置完成后,日志将如下所示:

2024-03-26T23:30:42.680-04:00 DEBUG 9477 --- [main] org.hibernate.SQL: 
    select
        c1_0.id,
        c1_0.budget,
        c1_0.end_date,
        c1_0.name,
        c1_0.start_date 
    from
        campaign c1_0 
    where
        c1_0.start_date between ? and ?

虽然这种方法非常简单,但不推荐使用,因为它直接将所有内容输出到标准输出,而没有利用日志框架的任何优化功能。

此外,它不会记录预编译语句(Prepared Statement)中的参数值

2.2. 通过日志记录器(Loggers)

我们也可以通过在配置文件中设置日志级别来记录 SQL 语句:

logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
  • 第一行用于记录 SQL 查询;
  • 第二行用于记录预编译语句的参数绑定信息。

上述配置同样支持 format_sql 美化功能。

通过这些配置,日志将被发送到已配置的 appender。Spring Boot 默认使用 Logback,并附带一个标准输出 appender。

如果我们希望记录带有绑定参数的查询,还可以在 application.properties 中添加以下属性:

logging.level.org.hibernate.orm.jdbc.bind=TRACE

该属性将 Hibernate 的 JDBC 绑定日志级别设为 TRACE,从而记录详细的绑定参数信息:

org.hibernate.SQL : select c1_0.id,c1_0.budget,c1_0.end_date,c1_0.name,c1_0.start_date from campaign c1_0 where c1_0.start_date between ? and ?
org.hibernate.orm.jdbc.bind : binding parameter [1] as [DATE] - [2024-04-26]
org.hibernate.orm.jdbc.bind : binding parameter [2] as [DATE] - [2024-04-05]

3. 记录 JdbcTemplate 查询

当使用 JdbcTemplate 时,需要额外配置两个属性来启用 SQL 日志记录:

logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG
logging.level.org.springframework.jdbc.core.StatementCreatorUtils=TRACE
  • 第一行用于记录 SQL 语句;
  • 第二行用于记录预编译语句的参数。

配置后,日志输出将包含 SQL 语句和绑定参数,例如:

2024-03-26T23:45:44.505-04:00 DEBUG 18067 --- [main] o.s.jdbc.core.JdbcTemplate: Executing prepared SQL statement [SELECT id FROM CAMPAIGN WHERE name = ?]
2024-03-26T23:45:44.513-04:00 TRACE 18067 --- [main] o.s.jdbc.core.StatementCreatorUtils: Setting SQL statement parameter value: column index 1, parameter value [sdfse1], value class [java.lang.String], SQL type unknown

4. 记录所有类型的查询

使用拦截器(Interceptor) 是记录所有类型 SQL 查询的最佳方式。通过拦截 JDBC 调用,我们可以格式化并以自定义方式记录 SQL 查询。

datasource-proxy 是一个流行的用于拦截和记录 SQL 查询的库。首先,在 pom.xml 中添加其依赖:

<dependency>
    <groupId>com.github.gavlyukovskiy</groupId>
    <artifactId>datasource-proxy-spring-boot-starter</artifactId>
    <version>1.12.1</version>
</dependency>

然后,在配置文件中启用该库的日志:

logging.level.net.ttddyy.dsproxy.listener=debug

配置完成后,日志将包含查询、参数等详细信息,格式清晰美观:

Name:dataSource, Connection:15, Time:1, Success:True
Type:Prepared, Batch:False, QuerySize:1, BatchSize:0
Query:["select c1_0.id,c1_0.budget,c1_0.end_date,c1_0.name,c1_0.start_date from campaign c1_0 where c1_0.start_date between ? and ?"]
Params:[(2024-04-26,2024-04-05)]

重要提示:拦截器方式会记录来自 JPA、JPQL 和 PreparedStatement 的所有查询,因此是记录带参数 SQL 查询的最佳方案。

5. 工作原理

Spring/Hibernate 中生成 SQL 语句并设置参数的类本身已经包含了日志记录代码

但这些日志的级别被设置为 DEBUG(SQL)和 TRACE(参数),低于 Spring Boot 默认的日志级别(INFO)。

通过上述配置,我们只是将相关日志器的级别调整为所需级别,从而启用这些日志输出。

6. 结论

在本文中,我们介绍了在 Spring Boot 中记录 SQL 查询的几种方法,并探讨了如何记录 SQL 查询的绑定参数。最后,我们说明了为什么拦截器方式是记录带参数 SQL 查询的最佳选择。

如果项目中配置了多个 appender,还可以将 SQL 语句与其他日志分别输出到不同的日志文件中,以保持日志结构的清晰整洁。