Hyperf 中模型静态方法切换数据库连接需通过 $connection 属性声明或 on() 链式调用实现,仅对 find()、all()、first() 等静态读操作生效;关联查询需逐层显式指定 on();事务中须统一使用同一连接上下文。

Hyperf 中模型静态方法切换数据库连接,核心是让 find()、all()、first() 等读操作走指定连接,而不是默认的 default。这不是靠运行时动态调用,而是靠模型类内声明或查询链式指定来实现,且有明确生效边界。
模型类内声明 $connection 属性
在模型顶部直接指定连接名,是最简洁的静态切换方式:
- 写法示例:
protected $connection = 'log_db'; - 仅对静态查询方法有效:如
User::all()、User::where(...)->first()、User::find(1) - 对实例方法无效:如
(new User())->save()或$user->update(...)仍走default,不继承该属性 - 若需写操作也走非默认库,必须配合事务或手动切换连接(见下文)
静态查询链式指定连接(推荐用于临时/条件切换)
不修改模型代码,按需在调用时指定,灵活性更高:
- 基础用法:
User::on('report_db')->all()、User::on('read_pool_1')->where('status', 1)->get() - 支持链式组合:
User::on('log_db')->where('level', 'error')->orderByDesc('created_at')->limit(10)->get() - 注意:此方式只影响当前查询,不影响后续调用,无需重置
关联查询必须逐层显式指定
使用 with() 做预加载时,Eloquent 默认所有关联都走主模型的连接(或 default),不会自动继承父级的 on() 设置:
- 错误写法(posts 会回退到 default):
User::on('read_pool_1')->with('posts')->get() - 正确写法(每层关联独立指定):
User::on('read_pool_1')->with(['posts' => fn($q) => $q->on('read_pool_1')])->get() - 多级关联同理,例如
comments属于posts,也要再嵌套一层:fn($q) => $q->on('read_pool_1')->with(['comments' => fn($c) => $c->on('read_pool_1')])
搭配事务时需统一连接上下文
事务要求所有操作在同一连接上执行,不能混用不同连接:
- 正确做法:用
DB::connection('log_db')->transaction()包裹全部读写操作 - 避免混合:不要在
User::on('log_db')->first()后,直接调用$user->save()—— 因为 save 走 default,会报错或数据写错库 - 若需模型实例也走指定库,可先用
DB::connection('xxx')获取连接后,再 new 模型并手动设连接,但更推荐事务方式统一管理


















