1. 概述
Spring JDBC和JPA在原生JDBC API之上提供了抽象层,让开发者可以告别原生SQL查询。但在调试时,我们经常需要查看这些自动生成的SQL语句及其执行顺序。
本教程将介绍在Spring Boot中记录SQL查询的几种方法。
2. 记录JPA查询
2.1. 输出到标准输出
最简单粗暴的方式是在application.properties
中添加:
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 ?
⚠️ 虽然简单,但不推荐这种方式:
- 直接输出到标准输出,没有日志框架的优化
- 不会记录预编译语句的参数
2.2. 通过日志框架
更专业的方式是配置日志记录器:
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
✅ 第一行记录SQL语句,第二行记录预编译参数
✅ 美化属性同样生效
✅ 日志会输出到配置的appender(默认是logback)
要记录带绑定参数的查询,添加:
logging.level.org.hibernate.orm.jdbc.bind=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
时需要两个额外配置:
logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG
logging.level.org.springframework.jdbc.core.StatementCreatorUtils=TRACE
效果类似JPA配置:
- 第一行记录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. 记录所有类型的查询
拦截器是记录所有SQL查询的最佳方案。通过拦截JDBC调用,可以自定义格式记录SQL。
推荐使用datasource-proxy库,先添加依赖:
<dependency>
<groupId>com.github.gavlyukovskiy</groupId>
<artifactId>datasource-proxy-spring-boot-starter</artifactId>
<version>1.9.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和预编译语句
✅ 是记录带绑定参数SQL的最佳实践
5. 原理揭秘
Spring/Hibernate中生成SQL和设置参数的类本身就包含日志代码,只是日志级别被设为DEBUG
和TRACE
,低于Spring Boot默认的INFO
级别。
我们添加的配置只是将这些日志记录器调整到所需级别,就这么简单。
6. 总结
本文介绍了Spring Boot中记录SQL查询的几种方式:
- 标准输出(简单但不推荐)
- 日志框架(推荐)
- 拦截器(最佳实践)
重点解决了预编译参数的记录问题,并说明了拦截器方案的优越性。
进阶技巧:通过配置多个appender,可以将SQL日志和其他日志分离到不同文件,保持日志整洁。