Hyperf 不内置分库分表能力,需手动编码实现路由逻辑:先通过策略类计算分库名(如 db0/db1)和分表名(如 orders_5),再调用 Db::connection($conn)->table($table) 执行操作;Model 不支持动态表名,跨分片查询需手动遍历合并结果。

Hyperf 本身不内置分库分表能力,携程或类似业务若在 Hyperf 中实现 MySQL 分库分表,必须自己编码控制路由逻辑——不是靠框架自动识别 orders 表就拆,而是每次查/写前,显式算出该走哪个库、哪张表。
怎么让 Db::connection() 走指定分库?
关键不是改配置,而是运行时动态选连接名。Hyperf 的 Db::connection($name) 会从 config/autoload/databases.php 里找对应键的配置,所以你得提前定义好所有分库连接(比如 db0、db1),再用代码决定传哪个名字进去。
-
config/autoload/databases.php里至少声明两个连接:db0和db1,指向不同 MySQL 实例或同一实例不同 schema - 不能直接
Db::connection('orders_3')—— 这个名字必须是预设的连接名,不是表名 - 路由策略(比如
user_id % 2)必须在业务代码里计算,不能依赖 SQL 解析或注解自动推导 - 如果用了
Hyperf/DbConnection的读写分离配置,注意分库路由要绕过它:读写分离是基于连接池的,而分库是基于连接名的,二者叠加时需确保db0_slave这类名字也预先配好
getTableName() 怎么和 Db::table() 配合?
Hyperf 的 Db::table($name) 只负责指定操作哪张物理表,不校验是否存在,也不做任何路由。所以你必须先调用自定义策略类的 getTableName(int $userId) 算出真实表名(如 orders_5),再喂给 Db::table()。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 错误写法:
Db::table('orders')->where('user_id', 123)->get()—— 这查的是原表,不是分表,数据根本不在那儿 - 正确顺序:先算表名 → 再选连接 → 最后执行:
Db::connection($conn)->table($table)->where(...)->get() - 表名拼接别硬编码,比如
"orders_{$userId % 8}",应封装进策略类,避免散落在各处 - 注意表名大小写:MySQL 默认对表名大小写敏感(尤其 Linux 环境),
orders_5和ORDERS_5是两张不同的表
为什么不能用 @Table 注解或 Eloquent 自动路由?
Hyperf 官方 Model(基于 Hyperf/Database)不支持运行时动态表名。它的 $table 属性是静态字符串,无法根据参数实时变化;@Table 注解也是编译期绑定,不参与运行时路由决策。
- 试图重写
getTable()方法返回动态值?不行——底层Query\Builder在构造时已固化表名,后续不会重新获取 - 想用
Hyperf/Database/Model+ 分表?只能放弃 ORM 操作,退回到Db::connection()->table()->xxx()原生链式调用 - 如果坚持用 Model,唯一办法是为每张分表定义一个子类(如
Order0、Order1…),但维护成本爆炸,且无法按user_id动态实例化 - 携程内部若封装了增强版 Model,那属于定制 SDK,不在 Hyperf 标准能力范围内
跨分片查询(如全量统计)怎么写才不崩?
没有中间件代理(如 ShardingSphere-Proxy)时,全表扫描必须手动遍历所有分片组合,自己合并结果。Hyperf 不提供 UNION ALL 自动生成或结果集归并功能。
- 用策略类的
getAllShards()获取全部[connection => 'db0', table => 'orders_0']列表,然后 foreach 执行查询 - 别用
collect()->merge()直接拼数组——大数据量下内存溢出风险极高,应流式处理或写临时表 - 聚合函数(
COUNT、SUM)必须在应用层二次计算,例如每个分片返回count,最终加总;不能指望SELECT COUNT(*) FROM orders自动路由到所有分片 - ORDER BY + LIMIT 分页最危险:各分片取 top N 后再全局排序,容易漏数据或重复,必须用游标分页(cursor-based)替代 offset-based
真正麻烦的从来不是“怎么写第一行路由代码”,而是“怎么保证所有 insert、select、update、delete 都经过同一套路由逻辑,且事务边界清晰”。漏掉一个 Db::table('orders') 就可能把数据写错库,查不到还不好定位。


















