告别“问号SQL”!JFinal + p6spy 一键输出完整可执行 SQL,并附带SQL执行耗时,调试效率翻倍!
💡 再也不用猜参数值了!真实 SQL 直接打印,复制粘贴就能在数据库客户端运行
调试痛点:为什么我们看不到完整 SQL?
在 JFinal 开发中,我们看到的是这样的日志
SELECT * FROM user WHERE id = ?
明明传了 id=123,却只能看到一个 ? —— 这是 JDBC 的 PreparedStatement 机制导致的。虽然安全,但调试时极其痛苦:
❌ 无法直接复制到 Navicat 执行
❌ 无法验证 SQL 逻辑是否正确
❌ 排查慢查询无从下手
想让 JFinal 输出像下面这样的完整 SQL?
SELECT * FROM user WHERE id = 123
你只需集成 p6spy,2 分钟搞定!
💡 之前社区有人分享过(jfinal + log4jdbc)Jfinal中使用日志框架输出完整sql语句信息
💡 但是log4jdbc不支持自定义日志格式;不支持过滤特定 SQL(如 SELECT 1);年久失修:自 2015 年后无更新,不支持新 JDBC 特性(如 MySQL 8 的认证)
💡 p6spy 持续更新,兼容 Java 17/21、MySQL 8、PostgreSQL 15 等
💡 高并发场景下,p6spy 的过滤功能(exclude)能减少无效日志 IO,略优
p6spy —— Java SQL 日志神器
p6spy 是一个轻量级 JDBC 代理工具,它能:
拦截所有数据库操作
自动替换
?为真实参数值输出可直接执行的完整 SQL
支持执行耗时统计、批量操作日志等
💡 它不侵入业务代码,只需改配置,零成本接入!
三步集成 JFinal + p6spy(2025 最新兼容版)
第一步:添加 Maven 依赖
<!-- p6spy 核心 --> <dependency> <groupId>p6spy</groupId> <artifactId>p6spy</artifactId> <version>3.9.1</version> </dependency> <!-- SLF4J + Log4j2(p6spy 3.9+ 强制要求SLF4J)一般你的日志系统已经在用 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.12</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j2-impl</artifactId> <version>2.23.1</version> </dependency>
第二步:配置 spy.properties(放在 src/main/resources)
# 真实 JDBC 驱动 driverlist=com.mysql.cj.jdbc.Driver # 使用 SLF4J 输出日志 appender=com.p6spy.engine.spy.appender.Slf4JLogger # 自定义格式:输出完整 SQL + 执行时间 logMessageFormat=com.p6spy.engine.spy.appender.CustomLineFormat customLogMessageFormat=%(executionTime) ms | %(sql) # 过滤掉心跳检测等噪音 # 过滤掉连接/提交等非 SQL 日志 # 过滤 JFinal + Druid 的探测 SQL filter=true regex=true exclude=(?i).*select\s+1.*|.*where\s+1\s*=\s*2.*|.*SHOW\s+(VARIABLES|WARNINGS).*
💡 %(sql) 会自动将 ? 替换为真实值,如 id = 123
第三步:修改 JFinalConfig
public class AppConfig extends JFinalConfig {
@Override
public void configPlugin(Plugins me) {
... 原来配置不变
String url = "jdbc:mysql://localhost:3306/your_db?useSSL=false&serverTimezone=Asia/Shanghai";
String driver = "com.mysql.cj.jdbc.Driver"; //MySQL 5.6 及以上
boolean dev_mode = PropKit.use("config.properties").getBoolean("dev_mode",false);
... 原来配置不变
//>>>>>>>>>>>>>>>>>>添加以下代码>>>>>>>>>>>>>>>>>>
// 现在你只需要 加上两句代码,让 URL 加 p6spy 前缀
// 并使用P6SpyDriver驱动类
// 根据自己业务需求,建议生产环境不开启
if(dev_mode) {
// 自动插入 p6spy:
url = url.replaceFirst("^jdbc:", "jdbc:p6spy:");
driver = "com.p6spy.engine.spy.P6SpyDriver"; // 当使用p6spy url后,要使用p6spy代理驱动
}
//<<<<<<<<<<<<<<<<<<添加以上代码<<<<<<<<<<<<<<<<<<
... 原来配置不变
DruidPlugin dp = new DruidPlugin(url, "user", "pwd", driver);
}
}🔑 关键点:
- URL 必须以jdbc:p6spy:开头
- 驱动类必须是com.p6spy.engine.spy.P6SpyDriver
第四步:配置日志属性
1. (如果用的是log4j2)配置 log4j2.xml (放在 src/main/resources;)
<!-- p6spy 默认使用这个 Logger 名 --> <Logger name="p6spy" level="DEBUG" additivity="false"> <AppenderRef ref="Console"/> </Logger>
📌 Logger 名必须是
p6spy(注意大小写)!
2. (如果用的是log4j1)配置 log4j.properties(放在 src/main/resources;log4j已过时,仅限老项目,建议升级到log4j2)
# 在配置文件末尾加上 # 👇 关键:P6Spy 的 Logger 名是 "p6spy" log4j.logger.p6spy=DEBUG, console log4j.additivity.p6spy=false
3. (如果用的是Logback)配置 logback.xml(放在 src/main/resources)
<!-- p6spy 默认使用这个 Logger 名 --> <logger name="p6spy" level="DEBUG" additivity="false"> <appender-ref ref="CONSOLE"/> </logger>
效果展示:从此告别“猜参数”

业务代码
// JFinal 中任意位置
List<User> users = User.dao.find("SELECT * FROM user WHERE age > ? AND status = ?", 18, "active");控制台输出
2025-12-28 20:00:00 [XNIO-1 task-1] INFO p6spy - 1 ms | SELECT * FROM user WHERE age > 18 AND status = 'active'
✅ 完整 SQL 直接可用!
✅ 带引号的字符串、数字、日期全部正确转义!
✅ 执行耗时一目了然!
💡 总结:为什么建议 JFinal 开发者用 p6spy?
✅ 零代码侵入:只改配置,不碰业务
✅ 真实可执行 SQL:调试效率提升 200%
✅ 支持所有数据库:MySQL、PostgreSQL、Oracle 等
✅ 免费开源:Apache 2.0 协议,无商业限制
花 2 分钟配置,省下 50 小时猜参数的时间!
在你的 JFinal 项目中加入 p6spy,从此和“问号 SQL”说byebye 👋
调试从未如此轻松!