thinkphp不支持开箱即用的分库分表,必须应用层主动介入:分表需重写gettablename()、分库需db::connect()切换连接,中间件仅传参不执行,scope封装路由更高效,跨分片操作基本不可行。

ThinkPHP 本身不提供开箱即用的分库分表路由能力,所谓“配置文件搞定”是常见误解。真正的分库分表必须在应用层主动介入 SQL 构建流程,靠 database.php 里的静态配置无法实现动态路由——它只管连接参数,不管哪张表、哪个库该被查。
分库和分表是两件事,得分开设计
分表依赖模型层重写 getTableName() 和 getTablePrefix():前者返回不含前缀的真实表名(如 order_07),后者必须稳定返回原始配置值(不能动态拼),否则会重复加前缀;分库则必须在查询执行前切换底层 Connection 实例,靠 Db::connect($config) 或模型内调用 $model->db('xxx') 实现,且要确保事务、日志、缓存等上下文绑定到新连接。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
中间件是统一入口,但只负责“传参”,不负责“执行”
在中间件里提取分片键(如 $request->param('user_id')),校验合法性后存入容器:
Container::getInstance()->set('shard_key', $userId);
后续模型或 Query 类通过容器读取该值做路由计算。切忌在中间件里直接调 Db::connect()——此时连接尚未初始化,会污染默认连接池。
模型层用 scope 控制时机,避免过早计算
把分片逻辑写进 initialize() 是低效的:每次 new Model 都执行哈希或时间解析,哪怕实例最终没发起查询。正确做法是封装成 scope 方法,在链式调用时触发,例如:$order->scopeShard($userId)->where(...)->select();
scope 内部可缓存已计算的库/表名,支持复用;同时必须返回 $query,不能 return null;若涉及用户输入(如月份),需白名单校验(preg_match('/^\d{6}$/', $month)),禁止字符串拼接表名。
绕不开的硬约束:跨分片操作基本不可行
ThinkPHP 的 join、count()、group()、事务、软删除、自动时间戳等功能,默认只作用于单个物理表和连接。一旦分库,关联查询得手动拆解;分表后 UNION ALL 要自己循环查再合并结果;跨分片事务只能靠应用层补偿或最终一致性方案。没有银弹,只有取舍。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










