Hyperf查询构造器需显式绑定连接名,Db::connection('name')必须前置调用,不可链式追加或依赖上下文;连接名须全小写无特殊字符,各库配置须独立完整,跨库事务不支持。

Hyperf 查询构造器本身不自动感知多库配置,所有跨库操作都依赖显式指定连接名。关键不是“怎么写查询”,而是“在哪一步绑定连接”——顺序错、位置错、方式错,都会走默认库或报错。
连接名必须提前声明,不能靠环境变量推导
在 config/autoload/database.php 的 connections 数组中定义的每个键,就是后续可用的连接名。它必须是全小写、无点号、无大写字母的合法标识符(如 log_db、report_pg),否则 Db::connection('read.pool') 会直接抛出 Connection [read.pool] not found 错误。
- 每个连接需完整写出
driver、host、port、database、username、password,不可复用default的字段 - 若涉及不同数据库引擎(如 MySQL 5.7 和 PostgreSQL 14),必须分池配置,不能共用同一连接名
-
default连接建议保留但不启用,防止未显式指定时意外命中主库
Query Builder 必须先 connection() 再链式调用
Db::table() 或 Db::select() 默认永远走 default 连接,与 Model 层的 on() 完全隔离,不存在上下文继承。要查非默认库,必须第一步就调用 connection()。
- ✅ 正确:
Db::connection('log_db')->table('logs')->where('level', 'error')->get() - ❌ 错误:
Db::table('logs')->connection('log_db')->get()(connection()不是链式方法) - ❌ 错误:
Db::table('logs')->get()即使前一行刚执行过User::on('log_db')... -
Db::select()不接受连接参数,必须前置connection(),例如:Db::connection('report_pg')->select('SELECT * FROM summary')
Eloquent 模型指定连接有作用域限制
模型类内设 protected $connection = 'read_pool_1' 只对静态查询方法(all()、find()、where()->get())生效;对实例方法((new User())->save())无效,且事务中也不继承该设置。
- 关联查询默认仍走
default,必须逐层指定:User::on('read_pool_1')->with(['posts' => fn($q) => $q->on('read_pool_1')]) -
on()是最常用方式,但仅适用于读操作;写操作(save()、update())若指向只读从库,会触发SQLSTATE[HY000]: General error: 1290 - 事务只能绑定单个连接池:
Db::connection('db.write')->transaction(...),跨库事务不支持,MySQL 从库本身也不支持BEGIN
避免常见陷阱:字符集、认证协议与连接池参数
多库场景下,不同实例间协议兼容性差异比想象中更敏感。一个连接池配错,可能表现为握手超时、prepare 失败或类型转换异常。
- MySQL 8.0 默认用
caching_sha2_password,5.7 用mysql_native_password,需在连接参数中补'options' => [PDO::MYSQL_ATTR_SSL_MODE => PDO::SSL_NONE] - PostgreSQL 12+ 对 prepared statement 行为有变更,旧扩展可能报
prepared statement "pdo_stmt_" does not exist - 连接池
max_connections应按目标库实际max_connections设置,例如 MySQL 5.7 实例上限为 200,则其连接池建议 ≤150 - 读库建议加
'strict_type' => false和'fetch_mode' => PDO::FETCH_ASSOC,减少类型转换开销


















