查日志前先确认sql本身是否写错,90%的“sql报错”实为表结构与代码不一致所致;需用describe验证字段、getrawsql()获取完整sql手动执行、开启db日志并正确配置categories、记录异常时传exception实例而非字符串、按错误码区分连接层问题(如2006、1213)并针对性处理。

查日志前先确认是不是 SQL 本身写错了
很多“SQL 报错”根本不是框架问题,而是 SQL 语法或字段名写错。比如 Unknown column 'option_name' in 'field list' 这类错误,90% 是表结构和代码不一致导致的——wp_options 表被改过、前缀变了、或者插件删了字段。
实操建议:
- 直接连数据库,执行
DESCRIBE wp_options;(或你实际的表名),确认option_name确实存在 - 在 Yii 中打印出最终执行的 SQL:
$command->getRawSql(),别信日志里带问号的那条,它没展开参数 - 把
getRawSql()输出的完整 SQL 复制到 MySQL 客户端手动执行,看是否报同样错——能复现,就是 SQL 或数据层问题;不能复现,再查框架配置
开启 Yii 的 DB 日志并过滤 category
默认 Yii 不会记录所有 SQL,必须显式打开 yii\db\Command::query 和 yii\db\Command::execute 这两个 category 的日志,否则你只看到 PHP 异常,看不到哪条 SQL 崩了。
实操建议:
- 在 log 组件中加 target,
'categories' => ['yii\db\Command::query', 'yii\db\Command::execute'] - 级别设为
info或更高,避免漏掉 warning 级别的慢查询警告 - 别用
'categories' => ['*'],太吵,容易掩盖关键线索 - 确保
'enableLogging' => true且'flushInterval' => 1,不然日志延迟写入,问题发生后查不到
捕获异常时必须传 Exception 对象,不能只传字符串
Yii::error('DB failed', $e) 和 Yii::error('DB failed', $e->getMessage()) 看起来差不多,但后者完全丢掉了堆栈——你只能看到“失败”,看不到在哪一行、哪个模型、哪个事务里崩的。
实操建议:
- 所有
Yii::error()记录数据库异常时,第二个参数必须是Exception实例,如$e,不是$e->getMessage() - 需要补充上下文(比如 SQL、参数、用户 ID)时,用数组包装:
Yii::error('Query failed', ['exception' => $e, 'sql' => $sql, 'user_id' => \Yii::$app->user->id]) - 检查日志 target 的
except配置,别把exception字段给过滤掉了
排查连接层问题:2006、2013、1213 这些数字要当关键字搜
像 2006 MySQL server has gone away 或 ERROR 1213 (40001): Deadlock found 这类错误,不是 SQL 写错了,而是连接状态或并发控制出了问题。它们不会出现在 SQL 日志里,得从异常类型和堆栈反推。
实操建议:
- 捕获 PDO 异常时,用
$e->getCode()判断错误码,而不是只看消息文本 - 对 2006 类断连错误,重试前先
\Yii::$app->db->close()+\Yii::$app->db->open(),别等下次查询自动重连 - 对 1213 死锁,必须自己实现重试逻辑(最多 3 次,每次
usleep(50000)),Yii 不会自动帮你 retry - 查 InnoDB 死锁日志:
SHOW ENGINE INNODB STATUS\G,重点看LATEST DETECTED DEADLOCK段
PDOException vs yii\db\Exception)、错误码、堆栈第一行调用位置,比盲目改 SQL 有用得多。











