ThinkPHP6记录SQL日志需同时满足app_debug=true、database.debug=true、log.level包含'sql';日志存于runtime/log/年月/日_sql.log,格式为[sql]语句[Bind:...];支持Db::listen()实时监听及事件审计。

ThinkPHP6 记录数据库 SQL 执行日志,核心是让框架在 SQL 执行时主动捕获并写入日志。它不依赖手动 echo 或 dump,而是靠配置驱动 + 事件机制实现自动化记录。关键不在“能不能”,而在“是否满足触发条件”。
确保基础调试开关全部打开
SQL 日志不是默认开启的,必须同时满足三个条件:
-
app_debug = true:在
config/app.php或.env中设APP_DEBUG=true;deploy 为 true 会强制关闭所有调试行为,所以也要确认'deploy' => false -
database.debug = true:在
config/database.php的数据库连接配置里明确开启,TP6 默认为 true,但多库或自定义配置时容易遗漏 -
log.level 包含 'sql':在
config/log.php的'level'数组中加入'sql',例如:'level' => ['error', 'sql', 'info'];只写debug不行,sql是独立日志级别
查看日志文件位置与内容格式
满足上述配置后,每次数据库操作都会生成一条带 [ sql ] 前缀的日志,写入 runtime/log/年月/日_sql.log(如 runtime/log/202610/29_sql.log)。
日志内容形如:
注意:问号占位符是 PDO 预处理的正常表现,括号里的 Bind 是实际传入参数,两者结合才能还原真实语句。
动态监听单次或批量 SQL(适合调试)
不想翻日志?可用运行时监听快速定位问题:
- 用
Db::listen()注册一次性的回调:Db::listen(function ($sql, $time) { echo "" . htmlspecialchars($sql) . "
"; });
它会在每次查询/写入后立即触发,输出原始 SQL(含 ? 占位符) - 对 insertAll、saveAll 等批量操作,
Db::getLastSql()仍有效,但仅返回最后一条执行语句;若需完整展开值,推荐监听think\db\Query事件,用$query->getRawSql()和$query->getBind()拼接出可执行 SQL
生产环境安全审计建议
线上不能开 app_debug,但仍需审计 SQL?可行方案有:
- 关闭
app_debug,但保留database.debug = true和log.level = ['sql']—— TP6 允许这种组合,SQL 仍会记录,只是不显示在页面 Trace 信息中 - 监听
db_execute系统事件,在app/event.php中注册处理器,将 SQL、绑定参数、执行耗时、调用栈等结构化写入独立审计日志通道(避免和业务日志混在一起) - 禁用
trigger_sql(旧版兼容项),改用database.logger.sql = true(TP6.1+ 推荐),更符合日志管道设计
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











