SQL错误被静默吞掉是因为deploy为true时debug失效,且PDO默认ERRMODE_SILENT;需设deploy=false、debug=true,并在pdo_params中配置PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION。

SQL错误没打出来?检查thinkphp数据库配置里的debug和deploy
ThinkPHP默认在生产环境(APP_DEBUG = false)下会关闭SQL错误输出,连日志都不写——不是没报错,是被静默吞掉了。关键看两个配置项:debug控制是否记录SQL和错误,deploy决定是否启用部署模式(会强制关闭调试)。只要deploy为true,哪怕debug设成true也无效。
-
database.php中确认'debug' => true,且'deploy' => false - 如果用的是
.env,确保APP_DEBUG=true,且没有APP_DEPLOY_MODE=true - 线上环境想保留SQL错误日志?必须关掉
deploy,不能只靠APP_DEBUG
日志里只有SQLSTATE[HY000]这种泛错误?开PDO::ATTR_ERRMODE直连报错
ThinkPHP底层用PDO,默认错误模式是PDO::ERRMODE_SILENT,出错只返回false,不抛异常,所以日志里只有模糊的SQLSTATE码,看不到具体MySQL错误信息(比如“Duplicate entry”或“Unknown column”)。得让PDO主动报错。
- 在
database.php的params里加:PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION - 注意:ThinkPHP 6.0+ 的
pdo_params字段才是正确位置,老版本可能叫params - 开了之后,SQL错误会直接抛
PDOException,日志里就能看到完整错误消息和SQL语句
查不到SQL执行耗时和绑定参数?用Db::getLastSql()和Db::getRealSql()
光有错误日志不够,很多问题出在参数绑定或隐式类型转换上。比如where('id', $id)传了个字符串'1',但字段是INT,MySQL可能不走索引——这种细节日志里不会体现,得手动捞真实SQL。
-
Db::getLastSql()返回带问号占位符的SQL(如SELECT * FROM user WHERE id = ?) -
Db::getRealSql()返回替换完参数的可执行SQL(如SELECT * FROM user WHERE id = 1),但注意:它只对最近一次查询有效,且需在查询后立刻调用 - 别在异常捕获块外调用
getRealSql(),中间穿插其他查询会覆盖结果
日志文件写满或权限不对?确认runtime/log路径和log.level
即使配置全开,日志也可能根本没生成——常见原因是runtime/log目录不可写,或者log.level设太高,把sql级别的日志过滤掉了。
立即学习“PHP免费学习笔记(深入)”;
- 检查
runtime/log是否存在、权限是否为755或777(Linux下尤其注意) - 在
log.php中确认'level' => ['sql', 'error', 'info'],不能只留['error'] - ThinkPHP 6 默认SQL日志归在
sql通道,对应日志文件是runtime/log/sql/xxx.log,不是error或info目录下的
最常被忽略的是deploy开关和pdo_params的位置——配错一个,SQL错误就永远藏在黑盒里。



















