Hyperf数据库读写分离需显式指定连接池,非自动SQL类型识别路由;正确配置中read与write为同级键,各自包含完整连接参数,查询须调用Db::connection('mysql::read')等显式方法,事务内禁止使用read连接。

Hyperf 的数据库读写分离不是靠自动识别 SQL 类型来路由,而是由你显式指定使用 read 或 write 连接池 —— 配置了 read/write 组只是第一步,不调用对应方法,流量全走默认连接池。
database.php 里配置 read/write 组的正确写法
Hyperf 使用 hyperf/database,其连接配置支持 read 和 write 两个顶层键,而非在单个 mysql 下嵌套。常见错误是把 read 写成子数组塞进某个连接名里,结果被忽略。
正确结构示例如下:
'mysql' => [
'driver' => 'mysql',
'read' => [
'host' => '192.168.1.10',
'port' => 3306,
'database' => 'test_db',
'username' => 'reader',
'password' => 'xxx',
],
'write' => [
'host' => '192.168.1.20',
'port' => 3306,
'database' => 'test_db',
'username' => 'writer',
'password' => 'xxx',
],
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'strict' => true,
'pool' => [
'min_connections' => 1,
'max_connections' => 10,
],
],
-
read和write是同级键,必须和driver、charset等并列 - 它们各自是完整连接配置数组,可独立设置
host、username、pool等,不需要复用主配置 - 如果只配了
read没配write,或反之,缺失的一方会 fallback 到主配置(即同级其他字段),但容易引发意外交互,建议显式配齐
查询时必须显式调用 connection('mysql::read')
Hyperf 不会根据 select/update 自动路由。即使你配了 read 组,所有 Db::table(...)->get() 默认仍走 write 连接(即主库),除非你手动切过去。
立即学习“PHP免费学习笔记(深入)”;
常用方式:
- 临时切换:
Db::connection('mysql::read')->table('users')->where('id', 1)->first() - 封装一个只读服务:在 Repository 中固定使用
Db::connection('mysql::read')实例 - 避免全局改写
Db默认连接,因为事务、写操作必须走write,混用会导致主从延迟读到旧数据甚至报错
注意:mysql::read 中的 ::read 是固定后缀,不能写成 mysql.read 或 mysql_read —— 这是 Hyperf 解析器约定的命名规则。
事务中禁止使用 read 连接
事务必须全程绑定同一个物理连接,否则会抛出 HY000: PDO::beginTransaction(): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active 类似错误,本质是连接不一致导致状态错乱。
- 任何
Db::transaction()块内,所有查询都必须走write连接 - 即便你在事务里只做
SELECT,也不能用mysql::read—— 因为事务上下文锁定了连接资源 - 需要“事务内查最新态”时,只能走主库;想缓解压力,应提前在事务外用
mysql::read做非关键预查
健康检查与故障转移不在默认能力范围内
Hyperf 的 read/write 配置只是静态声明,不包含节点探活、自动剔除失败从库、权重轮询等逻辑。如果某台从库宕机:
- 请求该
read节点会直接抛出 PDO 连接异常 - 不会自动 fallback 到其他
read节点(Hyperf 当前版本不支持多从库配置) - 若需多从库,得自己扩展
ConnectionResolverInterface,重写resolveWriteConnection和resolveReadConnection方法,手动实现负载逻辑
也就是说,databases.php 里的 read 只接受一个数组,不是数组的数组 —— 这点和 Laravel 的配置方式不同,别照搬。



















