hyperf单应用挂载多个数据库连接的核心是配置独立连接池、命名全小写无点号、运行时显式切换;必须在database.php中为每个库完整声明参数,不可复用default,不同版本或协议数据库须分池,eloquent需用on()或$connection指定,原生查询须前置db::connection(),跨库事务不支持。

Hyperf 单应用挂载多个数据库连接,核心是配置独立连接池、命名规范明确、运行时精准切换。不是简单加几行配置就能生效,稍有疏忽就会 fallback 到 default 或报 Connection not found 错误。
连接池命名与配置要点
每个数据库连接必须定义在 config/autoload/database.php 的 'connections' 数组中,且满足以下硬性要求:
- 连接名全小写、不含点号(.)、下划线可接受但不推荐;例如
read_pool_1✅,read.pool❌,DbWrite❌ - 不能复用
default配置块;写库如db_write、读库如report_db必须显式声明host、port、database、username、password全部字段 - 不同协议或大版本数据库(如 MySQL 5.7 vs 8.0、MySQL vs PostgreSQL)必须分池配置,不可混用;建议在连接名中体现语义,例如
mysql_v80_rds、pgsql_v14_cloud - 每个连接的
pool子项需显式启用并调优:'enable_pool' => true,'max_connections'按实际实例承载力设(如 MySQL 5.7 实例 max_connections=200,则连接池建议 ≤150)
运行时切换连接的三种方式
Hyperf 不会自动继承上下文,必须显式指定连接目标:
-
Eloquent 模型层:在模型类中声明
protected $connection = 'read_pool_1';,仅对User::all()、User::find(1)等静态查询生效;(new User())->save()仍走 default,需配合on()使用 -
链式 on() 方法:最常用,适用于绝大多数读操作,如
User::on('read_pool_1')->where('status', 1)->get();注意save()、update()等写操作若指向只读从库,会触发 SQLSTATE[HY000]: General error: 1290 -
DB 门面直切:原生查询和事务必须前置
Db::connection('xxx'),顺序不可颠倒;例如Db::connection('log_db')->table('logs')->where('level', 'error')->get();事务Db::connection('report_db')->transaction(...)只绑定单个连接池,跨库事务不支持
关联查询与多库协作细节
关联加载默认不继承主模型的连接设置,必须逐层显式指定:
-
User::on('read_pool_1')->with(['posts' => fn($q) => $q->on('read_pool_1')])—— 漏掉posts的on(),它就会回退到default连接 - 若关联模型本身也需走不同库(如
Post查report_db),则其模型内也要设$connection = 'report_db',或在 with 中覆盖 - 避免在模型中硬编码连接名;可通过构造参数或上下文注入动态决定,提升可测试性与灰度能力
安全与调试建议
多库配置容易因命名/路径/环境错位导致静默降级,上线前务必验证:
- 启动后检查日志是否输出
Connection [xxx] registered,确认所有连接池已加载 - 用
Db::connection('xxx')->select('SELECT 1')手动探测各连接连通性 - 禁用
default连接池(不配置或注释掉),防止未显式指定时意外命中主库造成从库写入 - 连接池
wait_timeout建议设为 2.0–3.0 秒,太小易触发WaitTimeoutException,太大则阻塞感知迟钝











