thinkphp 8 连接池报错的根本原因是db::table()默认不走连接池,必须显式调用db::pool()->table();pool配置仅在swoole协程模式(php think swoole)下生效,且需通过config/swoole.php配置、tp≥8.0.12、swoole≥4.8.0及think-swoole≥3.1.0配合,fpm下所有pool设置均无效并加剧连接堆积。

ThinkPHP 8 升级后连接池报错,基本不是配置写错了,而是根本没走连接池——Db::table() 默认不进池,pool 配置写在 database.php 里完全无效,FPM 下硬开 'pool' => true 反而会让连接堆积更严重。
为什么 Db::table() 调用不走连接池
TP8 的连接池不是全局拦截器,它不会自动把所有数据库操作路由过去。你得显式告诉框架:“这次我要用池子”。
-
Db::table('user')->select()→ 每次新建 PDO 实例,走传统短连接 -
Db::pool()->table('user')->select()→ 复用池中空闲连接 - 模型类(如
UserModel)默认也不走池,除非你在db()方法里手动返回Db::pool()实例
config/swoole.php 才是唯一有效配置位置
原生 config/database.php 中任何 pool、max_connections 字段都无效;TP8 不原生支持连接池,必须依赖 topthink/think-swoole 扩展,且配置入口只在 config/swoole.php 的 database 节点下:
'database' => [
'enable' => true,
'min_connections' => 5,
'max_connections' => 50,
'wait_timeout' => 3.0,
'heartbeat' => 30,
],
-
enable必须设为true,否则其他参数全被忽略 -
max_connections是池中最多维持的连接总数(忙碌 + 空闲),不是并发数 -
wait_timeout是协程等待空闲连接的超时时间(秒),设太小会频繁抛ConnectionPoolTimeoutException
FPM 和 Swoole 模式必须严格区分
连接池只在 php think swoole 启动的 Swoole 协程环境中生效;php think run(即 FPM)下所有 pool 配置和 Db::pool() 调用都会静默退化为短连接。
- 运行模式确认命令:
php think env:show | grep APP_MODE,输出swoole才对 - TP 版本必须 ≥
8.0.12,早期 8.0.x 存在协程适配 bug,连接不归还 - Swoole 扩展版本需 ≥
4.8.0,think-swoole需 ≥3.1.0
PDO 驱动在协程下有线程安全风险
TP8 默认用 pdo_mysql,但它在协程环境不安全:多个协程共用一个 PDO 实例可能触发 MySQL server has gone away 或字段错乱。
- 必须切换到
mysqlnd+Swoole\Coroutine\MySQL兼容层(think-swoole会自动适配) - 验证方式:同一协程内多次调用
Db::pool()->getPdo(),应返回相同 PDO 实例 - 若仍用 PDO,
params中必须显式传PDO::ATTR_PERSISTENT => false,生产环境默认禁用持久化
最容易被忽略的一点:三层限制必须对齐——MySQL 的 max_connections、Swoole 的 worker_num、连接池的 max_connections,三者中最小的那个才是实际瓶颈。光调大池子没用,MySQL 拒绝新连接时,报的还是 Too many connections。











