Hyperf中必须为不同版本或部署方式的数据库实例单独配置连接池,因认证协议、SQL模式等不兼容;需语义化命名、显式声明driver及pool参数,并通过Db::connection()运行时切换。

Hyperf 分布式项目中统一管理多数据库连接,核心在于配置集中化、运行时可切换、语义清晰且避免隐式依赖。不能靠硬编码或分散的 config 文件拼凑,而要依托框架的连接池机制与配置驱动能力。
配置层面:按数据源语义独立定义连接池
在 config/autoload/database.php 中,每个数据库实例(哪怕同是 MySQL)只要存在版本差异、部署方式不同(如 RDS vs 自建)、读写角色不同,就必须单独声明连接名和完整配置块:
- 连接名全小写、无点号/大写字母(如 mysql_v80_write、pgsql_report_read),否则
Db::connection('xxx')会报 Connection [xxx] not found - 每个连接必须显式声明
driver、host、port、database、username、password,不可复用default的字段 -
pool子项需按实际承载力调优:max_connections建议设为数据库实例max_connections的 70%~80%,MySQL 5.7 实例设 200,则连接池 max 设 150 更稳妥 - 跨版本需补协议适配参数,例如 MySQL 8.0 加
'options' => [PDO::MYSQL_ATTR_SSL_MODE => PDO::SSL_NONE],5.7 可能需启用模拟预处理PDO::ATTR_EMULATE_PREPARES => true
运行时:统一入口 + 显式绑定
所有数据库操作必须通过 Db::connection('xxx') 显式指定连接池,不能依赖上下文继承或默认行为:
- Query Builder:先
Db::connection('log_db'),再链式调用table()、where()、get();顺序颠倒会走default - Eloquent 模型:可在类中设
protected $connection = 'report_db',但仅对all()、find()等静态方法生效;new User()->save()仍走default,需配合on()使用 - 关联查询必须逐层指定:如
User::on('read_pool')->with(['posts' => fn($q) => $q->on('read_pool')]),漏掉任一环节就会回退到主库 - 事务只支持单连接池:跨
mysql_v80_write和pgsql_report_read的事务会直接报错,MySQL 从库本身不支持BEGIN
分布式场景下的关键约束
在多节点部署中,连接管理还需兼顾一致性与隔离性:
-
default连接池建议保留不用或设为禁用状态,防止未显式指定时意外命中主库,造成从库写入失败 - 读写分离不是加几个配置就行——写库命名如
db.write,读库如read_pool_1,模型调用on('read_pool_1')后,save()会因从库只读触发SQLSTATE[HY000]: General error: 1290 - 不支持同一连接池混用不同引擎或大版本(如 MySQL 5.7 + 8.0),认证协议、字符集、系统变量响应均不兼容,必须物理隔离
- 灰度升级时可通过
ConfigInterface动态修改内存中连接配置,无需重启服务,适用于 A/B 测试或分批切流


















