yii2默认不自动fallback是因为其connection设计为严格抛出yii\db\exception而非静默降级,需手动try/catch捕获后切主库重试,并配合serverstatuscache缓存节点状态以避免反复试探。

Yii2 默认不自动把失败的从库查询切到主库,必须手动加容错逻辑,否则直接抛异常导致 500 错误。
为什么不能自动 fallback
Yii2 的 Connection 在从库连接失败或查询出错时,不会静默降级,而是立即抛出 yii\db\Exception。它没有内置的“失败即切主库”机制,也不做健康状态缓存(除非你显式配置 serverStatusCache)。
必须用 try/catch 主动捕获并重试主库
对确定是只读、但又不能容忍从库不可用的场景,推荐在业务层包裹查询逻辑:
- 先尝试走从库(默认行为或显式调用
Yii::$app->db->slave) - 捕获
\yii\db\Exception后,改用主库重试 - 避免重复执行写操作,只对纯查询做 fallback
示例:
```phptry {
$data = Yii::$app->db->createCommand('SELECT * FROM order WHERE status=1')->queryAll();
} catch (\yii\db\Exception $e) {
// 从库不可用,切主库重试
$data = Yii::$app->db->master->createCommand('SELECT * FROM order WHERE status=1')->queryAll();
}
配合 serverStatusCache 避免反复试探坏节点
启用服务器状态缓存后,Yii 会记住某台从库在 serverRetryInterval(默认 60 秒)内是否宕机,跳过无效连接尝试:
- 配置
'serverStatusCache' => ['class' => 'yii\caching\FileCache'] - 设置
'serverRetryInterval' => 30(单位秒) - 该缓存只影响从库选择阶段,不影响查询执行本身
哪些查询真会走从库?别被表象骗了
不是所有 SELECT 都能落到从库,关键看调用方式和上下文:
- ✅ 走从库:
User::find()->one()、Yii::$app->db->createCommand()->queryAll() - ❌ 不走从库:
new \yii\db\Command()、事务中的find()、findOne()(可能触发隐式锁)、带joinWith()的关联查询 - ⚠️ 注意:
createCommand($sql)->queryOne()不经过 Yii 的路由判断,必须显式写成Yii::$app->db->slave->createCommand($sql)->queryOne()











