连接池命名必须全小写且不含点号,如read_pool_1、db_write;Model层on()仅对查询生效,save()会因从库只读失败;with()关联需逐层指定连接池;Db::transaction()不支持跨池操作。

连接池命名必须全小写且无点号
Hyperf 会严格校验连接池名,Db::connection('read.pool') 这种带点号的写法直接报错 Connection [read.pool] not found。配置文件里所有连接池名只能是纯小写字母 + 下划线,比如 read_pool_1、db_write,不能出现大写、点、中划线或数字开头。
Model 层 on() 方法只对查询生效,save() 会失败
User::on('read_pool_1')->where('id', 1)->first() 没问题,但 User::on('read_pool_1')->save() 必然触发 SQLSTATE[HY000]: General error: 1290 —— 因为从库默认启用 --read-only,不允许写入。模型层强制走读库仅适用于 SELECT 类操作;INSERT/UPDATE/DELETE 必须显式用 on('db_write') 或依赖默认写池。
关联查询 with() 必须逐层指定连接池
Eloquent 的 with() 不继承父查询的连接池,哪怕你写了 User::on('read_pool_1')->with('posts'),posts 表仍走 default。正确写法是:
User::on('read_pool_1')->with(['posts' => fn ($q) => $q->on('read_pool_1')])- 如果 posts 关联了 comments,还得继续嵌套:
->with(['posts' => fn ($q) => $q->on('read_pool_1')->with(['comments' => fn ($c) => $c->on('read_pool_1')])])
漏掉任意一层,那一层就会回退到 default,可能意外写入从库或查出旧数据。
Db::transaction() 不支持跨连接池
Db::transaction() 只能绑定一个连接池,传入闭包里所有 DB 操作都必须在同一个池内完成。写法 Db::connection('db_write')->transaction(function () { Db::connection('read_pool_1')->table(...)->insert(...); }) 会直接报错,MySQL 从库不支持 BEGIN,Hyperf 也不做跨池事务协调。需要事务的场景,全部操作必须落在 db_write 池;读操作想进事务上下文,只能走主库。
最容易被忽略的是:原生查询(Db::table())和 Eloquent 查询完全隔离,前者不会继承后者的 on() 设置;而事务一旦开启,就锁死当前连接池,连 Db::select() 都得先 Db::connection('xxx') 再调用,顺序错一步就走错库。



















