开启tp数据库日志需同时满足app_debug=true且log.level包含'sql',否则无法输出sql;调试单条查询优先用getlastsql(),预览sql逻辑用buildsql(),长sql或中文乱码需检查log.file_size和default_charset。

开启TP数据库日志后还是看不到SQL?检查app_debug和log.level
ThinkPHP默认只在app_debug = true时才记录SQL日志,生产环境关掉调试就完全静默。即使开了db.deploy或db.trace,没开调试也没用。
-
app_debug必须为true(通常在env或config/app.php里) -
log.level需包含sql,例如['error', 'sql', 'notice'],仅设info或debug不一定触发SQL输出 - 若用
Log::getLog()手动取日志,得确保调用时机在查询之后、响应之前,否则可能为空
想立刻看到某条查询的SQL?用getLastSql()而不是翻日志
getLastSql()是模型/查询构造器执行后最直接的抓手,比等日志文件更可控,适合调试单次查询逻辑。
- 必须在
select()、find()、update()等执行方法**之后**立即调用,比如:$list = Db::table('user')->where('id', 1)->select(); echo Db::getLastSql(); // ✅ 正确 - 不能在
where()链式调用中途调用,此时SQL还没组装完:Db::table('user')->where('id', 1)->getLastSql(); // ❌ 返回空或上一条 - 注意:
getLastSql()只返回**最后一条**,批量操作(如insertAll)会覆盖,要逐条查就得拆开或用buildSql()
buildSql()能预览SQL但不执行,适合验证拼接逻辑
当你要确认where条件是否真的加进去了、join表名有没有写错,buildSql()比等执行再看getLastSql()更安全——它不碰数据库,纯字符串生成。
- 用法简单:
Db::table('user')->where('status', 1)->buildSql(),返回带问号占位符的原始SQL - 注意:它不会替换绑定参数,所以看到的是
WHERE status = ?,不是WHERE status = 1;真要看完整语句还得配合getLastSql()或日志 - 对子查询、闭包
where支持良好,但复杂视图或存储过程调用可能不准确
日志文件里SQL被截断或乱码?检查log.file_size和default_charset
SQL长一点(比如含大JSON字段或复杂GROUP_CONCAT),日志里就变成... (2048 bytes),或者中文变???,这不是TP问题,是日志底层配置漏了。
-
log.file_size默认可能是2MB,但单条SQL超长时会被截断,建议设为0(不限制)或足够大的值(如10 * 1024 * 1024) - 如果SQL里有中文、emoji,而
default_charset不是utf8mb4,日志文件可能写入失败或乱码,需同步确认MySQL连接也用了charset=utf8mb4 - 日志路径权限不足也会静默丢SQL,可临时把
log.path指向/tmp测试是否写入成功
TP的SQL追踪本质是“调试开关+执行钩子+日志管道”三者咬合,缺一不可。最容易忽略的是app_debug和log.level的联动关系——光开一个没用,两个都得对上。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










