hyperf 不支持同一连接池混用不同数据库引擎或大版本,因认证协议、sql 模式、系统变量等存在不兼容;必须为每个协议/行为差异大的实例单独配置连接池,显式声明 driver、pool 参数并按实际承载力调优。

Hyperf 不支持“同一连接池混用不同数据库引擎”,比如让一个 default 连接池既连 MySQL 8.0 又连 MySQL 5.7,或同时兼容 PostgreSQL。必须为每个**协议兼容性不同、驱动行为差异大**的数据库实例单独配置连接池。
为什么不能复用同一个连接池配置
Hyperf 的连接池是基于 PDO 驱动 + 协程封装的,而不同版本数据库(尤其是跨大版本)在认证协议、默认字符集、SQL 模式、系统变量响应上存在不兼容。例如:
- MySQL 8.0 默认使用
caching_sha2_password插件,而 5.7 是mysql_native_password;若共用连接池且未显式指定auth_plugin,部分连接会卡在 handshake 阶段 - PostgreSQL 12+ 引入了
prepared_statement行为变更,与 pgsql 扩展旧版本不匹配时,Db::select()可能抛出PDOException: ERROR: prepared statement "pdo_stmt_..." does not exist -
max_connections设置若统一按高版本调优,低版本实例可能因max_connections超限直接拒绝新连接,报错Too many connections
多版本数据库的正确配置方式
每个数据库实例(哪怕同属 MySQL)只要版本号或部署方式不同(如 RDS vs 自建、ProxySQL 后端分片),就应视为独立数据源,在 config/autoload/databases.php 中定义独立连接名和完整 pool 配置:
- 给连接起明确语义名,例如
mysql_v57_rds、mysql_v80_local、pgsql_v14_cloud,避免用db1/db2这类无含义命名 - 每个连接必须完整声明
driver、host、port、version(非必需但建议写进注释)、charset和pool子项 -
pool内必须显式设enable_pool => true,且min_connections/max_connections按该实例实际承载力设置(例如 MySQL 5.7 实例 max_connections=200,则其连接池max_connections建议 ≤150) - 若涉及认证差异,需在连接参数中补全,例如 MySQL 8.0 加
'options' => [PDO::MYSQL_ATTR_SSL_MODE => PDO::SSL_NONE, PDO::ATTR_EMULATE_PREPARES => false],5.7 可能需设PDO::ATTR_EMULATE_PREPARES => true
运行时动态切换连接池(不重启)
Hyperf 允许在框架启动后通过 ConfigInterface 修改内存中连接配置,适用于灰度升级或 A/B 测试场景:
- 监听
Hyperf\Framework\Event\AfterStart事件,在回调中注入ConfigInterface - 调用
$config->set('databases.mysql_v80_canary', [...])注入新连接配置(含完整pool) - 后续代码中用
Db::connection('mysql_v80_canary')显式指定,不能依赖default别名 - 注意:此方式新增的连接池不会自动注册到 Metrics,需手动调用
ConnectionPool::register()(Hyperf v3.1+ 支持)
事务与跨版本查询的边界限制
Hyperf 的 Db::transaction() 仅作用于单个连接池。跨多个版本数据库(如 mysql_v57_rds + mysql_v80_local)无法开启分布式事务:
- 不能在一个
Db::transaction()闭包里同时操作两个不同连接名的表,否则第二个Db::connection(...)->table(...)会新开连接,脱离事务上下文 - 若业务强依赖跨库一致性,需改用最终一致性方案(如发 MQ、写 binlog 订阅)而非本地事务
- 读操作可安全跨连接,但要注意各版本对
JSON字段解析、窗口函数语法支持度不同,Db::raw()中 SQL 必须按目标版本校验
真正麻烦的不是配多少个连接池,而是每个池的 wait_timeout 和后端数据库的 wait_timeout 是否对齐——差 1 秒都可能导致协程归还连接时被服务端主动断开,下次取出就报 MySQL server has gone away。











