告别“问号SQL”!JFinal + p6spy 一键输出完整可执行 SQL


告别“问号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>

效果展示:从此告别“猜参数”

微信截图_20251228222512.png

业务代码

// 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 👋
调试从未如此轻松

评论区

听风道长

2025-12-29 15:18

太实用了!!

热门分享

扫码入社