yii多数据库需显式配置多个db组件并重写模型getdb()方法;读写分离须手动指定主从连接,不支持自动路由,且事务内禁止跨库操作。

Yii 支持多数据库配置,但「多个 db 组件 + 模型显式指定」是唯一稳定可靠的方式;读写分离不是开箱即用的功能,必须手动拆分主从连接并干预查询路径,否则所有操作仍走默认 db。
多个数据库组件必须显式声明 class
在 config/web.php 的 components 中添加第二个数据库时,不能只写 DSN 和账号密码,class 是强制字段。漏掉它会报错:Object configuration must be an array containing a class element。
-
db2、logdb、statdb这类自定义 ID 都要配全:'class=>yii\db\Connection' - 每个连接的
dsn必须指向不同数据库(哪怕同主机),例如mysql:host=localhost;dbname=app_main和mysql:host=localhost;dbname=app_log - 如果复用同一套账号密码,仍需为每个组件单独写一遍
username和password,不支持引用或变量插值
模型中重写 getDb() 才能绑定特定数据库
ActiveRecord 默认只认 db 组件。要用 db2,必须在对应模型里覆盖静态方法 getDb(),返回 Yii::$app->get('db2')。
- 生成 Model 时用 Gii,Database Connection ID 要手动选
db2,否则生成的代码仍是return Yii::$app->db - 不要试图在控制器里临时切换
Yii::$app->db = Yii::$app->db2—— 这会影响全局,且下次请求又恢复,极难调试 - 若多个模型共用同一非默认库,建议抽一个基类,比如
LogActiveRecord,里面统一写return Yii::$app->get('logdb'),再让各日志模型继承它
读写分离需手动控制连接选择
Yii 本身不提供 master-slave 自动路由。所谓“读写分离”,本质是:写操作走主库(如 db_master),读操作走从库(如 db_slave),全靠你代码里决定用哪个组件。
- 写操作保持原样:
User::getDb()返回db_master,save()、delete()等自然走主库 - 读操作需显式换连接:比如查统计报表,新建一个
ReportQuery类,在其getDb()中返回db_slave;或者直接用 DAO:Yii::$app->db_slave->createCommand($sql)->queryAll() - 事务内禁止跨库操作:一旦
beginTransaction()在db_master上开启,后续所有save()、find()都必须在同一连接上完成,否则抛异常
常见错误:连接未 open 就被调用
配置完组件后,Yii 不会自动连接数据库。首次执行 SQL 时才触发 open(),此时若账号错、网络不通、库不存在,会直接报 PDO 异常,而不是配置阶段报错。
- 上线前务必加健康检查:在
console/controllers/HealthController.php里写个 action,对每个 db 组件调用$db->open()并捕获异常 - 开发环境可开
enableSchemaCache => false,避免缓存旧表结构导致Column not found类错误 -
charset务必设为utf8mb4,尤其当字段含 emoji 或生僻字时,utf8会静默截断
真正麻烦的不是配置几个 db 组件,而是模型层和业务逻辑层得全程知道“这条数据该从哪来、往哪写”。一旦某个查询本该走从库却用了主库,或事务里混入了从库查询,问题往往延迟暴露、难以复现。











