核心是让ActiveRecord或Command明确使用指定db组件,而非默认Yii::$app->db;Model中重写getDb()可固定库,createCommand需直接调用目标db组件,迁移需手动切换$this->db。

直接结论:更新指定库的表数据,核心不是“改哪条 SQL”,而是让 ActiveRecord 或 Command 明确知道该用哪个 db 组件——否则它默认走 Yii::$app->db,跟你配了 5 个库也没关系。
ActiveRecord 更新时强制指定数据库连接
ActiveRecord 默认调用 getDb() 静态方法获取连接,这个方法可以被覆盖。如果你的 Model 要固定写入某个库(比如 db2),就在 Model 类里重写它:
public static function getDb()
{
return Yii::$app->db2;
}
这样所有 save()、updateAll()、deleteAll() 都自动走 db2。注意:find() 查询也受此影响,不是只改不查。
常见错误现象:Call to a member function insert() on null —— 多半是 Yii::$app->db2 没在配置里注册,或组件名拼错(比如写成 db_2 但配置里是 db2)。
使用场景:
- 用户中心数据写主库,日志类数据写从库或独立日志库
- 分库后某类订单固定落在
db_order_01 - 测试环境用
db_test,但 Model 不想改名,只换连接
createCommand 更新时不依赖 Model,直接选库
如果你不用 ActiveRecord,而是用原生命令操作(比如批量更新、跨表 join 更新),就别碰 Yii::$app->db,直接拿你要的组件:
Yii::$app->db2->createCommand()
->update('order', ['status' => 2], 'id = 1001')
->execute();
关键点:
-
createCommand()是 Connection 类的方法,所以必须从具体 db 组件上调用,不能从Yii::$app直接调 - 不支持链式切换:写完
db2->createCommand()后不能中途改成db3,得重新取组件 - 事务要手动绑定到目标库:
$transaction = Yii::$app->db2->beginTransaction();,混用会出错
运行时动态切库更新(不推荐但有时真得用)
极少数场景需要同一个 Model 实例在不同请求中写不同库(比如按租户 ID 分库),这时不能靠重写 getDb(),得运行时干预。可行但易错的做法是:
先断开旧连接,再改 DSN 和凭据,再重连:
Yii::$app->db_test->close(); Yii::$app->db_test->dsn = 'mysql:host=10.10.10.11;dbname=tenant_abc'; Yii::$app->db_test->username = 'abc_user'; Yii::$app->db_test->password = 'xxx'; Yii::$app->db_test->open();
容易踩的坑:
- 并发请求下改全局组件配置是线程不安全的,
db_test可能被其他请求同时读写 - 没
close()就直接open(),PDO 可能报 “Already connected” - 改完不
open(),后续命令会抛Connection is not established
更稳妥的替代方案是:用 new \yii\db\Connection([...]) 临时建一个连接对象,不污染应用级组件。
迁移文件里更新多库表结构要逐个执行
Yii2 的 yii migrate 默认只操作 db 组件。如果要在多个库上同步加字段,不能靠一个迁移文件“自动广播”,得显式指定目标库:
在迁移类里分别操作:
public function up($migration)
{
$this->db = Yii::$app->db1;
$this->addColumn('user', 'phone', $this->string());
$this->db = Yii::$app->db2;
$this->addColumn('user', 'phone', $this->string());
}
注意:
-
$this->db是 Migration 类的属性,默认是Yii::$app->db,可安全赋值为其他组件 - 别在
up()里混用多个库后不做隔离——比如db1建表失败,db2还继续跑,会导致状态不一致 - 生产环境严禁用
yii migrate/up 1批量跑未验证的多库迁移,必须单步确认每个库的结果
最常被忽略的一点:迁移文件里的 $this->db 切换只影响当前迁移类内部的 createTable() 等方法,不影响你手写的 Yii::$app->db2->createCommand() —— 那部分完全由你控制,别指望它自动跟着变。


















