Hyperf 3.1 不支持 Laravel 风格的 DB::connection('xxx'),读写分离需通过配置 default 连接的 read/write 子键实现,SELECT 自动走从库,写操作及事务强制走主库,手动切库仅支持额外配置独立连接名方式。

Hyperf 3.1 不支持 DB::connection('xxx') 这种 Laravel 风格的写法,也没有内置 DB::connection() 全局静态方法。它用的是依赖注入 + 连接管理器(ConnectionInterface 或 ConnectionPool)的方式,读写分离需通过配置驱动和连接池实现,不能靠手动调用 DB::connection('read') 切库。
✅ 正确做法:靠配置自动路由(推荐)
Hyperf 的数据库组件(hyperf/database)继承自 illuminate/database,支持 Laravel 风格的读写分离配置,但必须满足以下结构:
1. 配置 config/autoload/db.php 中的 default 连接含 read 和 write 子键
'default' => [
'driver' => 'mysql',
'host' => '127.0.0.1',
'port' => 3306,
'database' => 'test',
'username' => 'root',
'password' => '',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
// ⚠️ 共用配置必须放外层,read/write 内部只放 host/port 等差异化项
'read' => [
['host' => '192.168.1.10'], // 从库1(必须是数组)
['host' => '192.168.1.11'], // 从库2
],
'write' => [
'host' => '192.168.1.5', // 主库(必须是单元素关联数组)
],
'pool' => [
'min_connections' => 1,
'max_connections' => 10,
],
],? 关键点:
read必须是数组(哪怕只有一个从库也要写成[['host' => ...]])write必须是单个关联数组(不是['192.168.1.5'],而是['host' => ...])database/username/password等共用字段只能在外层写一次,否则会被忽略
2. 框架自动路由:SELECT 走从库,INSERT/UPDATE/DELETE/事务走主库
-
DB::table('users')->get()→ 自动选一个read节点 -
DB::table('users')->insert([...])→ 固定走write -
DB::transaction(...)内所有查询 → 强制走write(无论是否 SELECT) - Eloquent 查询(如
User::find(1))→ 默认也走读写分离逻辑
❌ 手动指定读库?Hyperf 不提供 DB::connection('read'),但可绕行
如果你确实需要强制走某个特定从库(比如查最新数据又不想进事务),有 2 种方式:
方式一:定义独立连接名(非读写分离模式)
在 db.php 中额外配一个只读连接:
'read_only_slave' => [
'driver' => 'mysql',
'host' => '192.168.1.10',
'port' => 3306,
'database' => 'test',
'username' => 'readonly_user',
'password' => 'xxx',
'charset' => 'utf8mb4',
'pool' => [/* ... */],
],然后在代码中显式获取:
use Hyperf\Database\ConnectionInterface;
use Hyperf\Database\ConnectionFactory;
public function index(ConnectionFactory $factory)
{
$slave = $factory->make('read_only_slave');
$result = $slave->select('SELECT * FROM users WHERE id = ?', [1]);
return $result;
}⚠️ 注意:这种方式绕过了读写分离自动路由,也不参与负载均衡或故障转移,适合临时强一致性读。
方式二:用 DB::connection()->getPdo() 临时切库(不推荐)
Hyperf 的 ConnectionInterface 实例本身不暴露“切换 read/write”的方法。强行操作底层 PDO 会破坏连接池和协程安全,容易引发 MySQL server has gone away,官方明确禁止直接操作 PDO 句柄。
? 补充提醒
- 事务内所有查询都走主库,这是硬性规则,无法覆盖
-
sticky = true(Laravel 的防延迟机制)Hyperf 暂未原生支持,如需避免主从延迟导致查不到刚写的记录,建议:- 在事务后加短暂 sleep(不优雅)
- 或业务上主动用
DB::connection('default')->getPdo()获取刚写入的连接句柄再查(需自己管理)
- 多从库时,默认使用随机策略选择,不支持轮询或权重配置(需自行扩展
ReadQueryStrategy)
Hyperf 的读写分离是配置驱动、运行时自动识别的,不是靠手动 DB::connection() 切换。想“指定读库”,本质是配好 read 数组,让框架去选;真要锁定某台,就单独配个连接名并手动拉起。


















