yii框架连接多个数据库需注册多个唯一id的yii\db\connection组件,模型通过重写getdb()指定连接,dao直接调用组件,读写分离须手动路由,跨库无事务一致性。

Yii 框架连接多个数据库,本质就是注册多个 yii\db\Connection 组件,并在模型或查询中显式指定用哪一个。不是靠“自动识别”或“魔法配置”,而是靠组件 ID + getDb() 方法绑定。
多个数据库连接必须注册为不同组件 ID
Yii 不允许两个组件共用同一个 ID(比如都叫 db),否则后注册的会覆盖前一个。你得给每个库起唯一名字,比如 db、logdb、statdb、reportdb。
常见错误现象:Unknown Component ID: logdb —— 说明你在模型里写了 return Yii::$app->get('logdb'),但 logdb 根本没在 components 数组里定义。
- 配置位置:统一写在
config/web.php或config/main-local.php的components下,别漏掉外层数组结构 - 每个连接必须包含
class、dsn、username、password,缺一不可 -
dsn字符串要严格格式化,例如:'mysql:host=mysql-log;dbname=logs;charset=utf8mb4';Docker 环境下host必须填容器名,不能写localhost - 敏感字段(如
password)建议用getenv('LOGDB_PASSWORD') ?: 'fallback',避免硬编码
模型怎么指定用哪个数据库
ActiveRecord 默认只认 db 组件。想让它连别的库,必须重写静态方法 getDb(),返回对应组件实例。
典型错误:只改了配置,没改模型,结果 LogEntry::find()->all() 还是查主库 —— 因为模型没声明用 logdb。
- 在模型类里加这个方法即可:
public static function getDb() { return Yii::$app->get('logdb'); } - 如果用 Gii 生成模型,创建时在 “Database connection ID” 输入框填
logdb,它会自动生成正确的getDb() - 不继承 ActiveRecord?用 DAO 时直接调用:
Yii::$app->logdb->createCommand(...)->queryAll() - 注意:每个模型只能绑定一个数据库连接;跨库 JOIN 需手动拼 SQL 或用视图,AR 不支持
读写分离不是开个开关,得靠组件拆分 + 逻辑路由
Yii 本身不内置“读写分离代理”,所谓读写分离,是人为把 master 和 slave 配成两个组件(如 db_master、db_slave),再根据操作类型决定用哪个。
容易踩的坑:save() 或 insert() 走了从库 —— 数据写不进去还查不到,因为从库只读。
- 写操作(
save()、delete()、updateAll())必须强制走db_master - 读操作(
find()->all()、count())可按需走db_slave,但得自己控制,比如封装一个SlaveQuery类 - 事务内所有操作必须走同一个连接,不能一半主库一半从库,否则报错
Cannot execute queries while other unbuffered queries are active - 不要试图在
getDb()里动态判断读写 —— AR 查询链(where()、orderBy())执行时并不知道最终是读还是写,只有到save()或all()才触发
最易被忽略的一点:多个数据库之间没有事务一致性。跨库 save() 加 commit() 只能保证单库原子性,没法做分布式事务。业务上需要强一致的场景,得靠消息队列+补偿,而不是指望 Yii 配置解决。











