ThinkPHP 5 没有原生数据库连接池,因核心类 think\db\Connection 不含池逻辑,仅支持短连接与请求内单例复用;database.php 中添加 pool 配置无效,所谓“连接池”需依赖 Swoole 协程生态或手动集成 PDOPool 实现。

ThinkPHP 5 没有原生数据库连接池配置项,所谓“配连接池”本质是绕过框架限制、手动接入协程池或调优底层连接复用机制。 直接在 database.php 里加 'pool' => [...] 或 'persistent' => true 不起作用,甚至可能引发事务污染、连接泄漏或状态错乱。
为什么 database.php 里找不到 pool 配置?
TP5 的数据库核心(think\db\Connection)不包含连接池逻辑,它只做短连接 + 请求生命周期内的单例复用。所谓“连接池”是社区或 Swoole 生态的补充方案,不是框架内置能力。
常见误操作包括:
- 在
database.php中硬加'pool' => ['enable' => true, 'min' => 5]—— TP5 完全忽略该字段,无任何效果 - 开启
'params' => [\PDO::ATTR_PERSISTENT => true]—— PDO 持久连接在 FPM 场景下极易导致连接数堆积、事务残留,官方明确不推荐 - 使用
Db::connect(['hostname' => ...])多次初始化 —— 每次都 new 新连接,彻底绕过复用机制
高并发下真正有效的连接管理方式
TP5 原生不支持协程,所以无法直接用 Swoole 的 PDOPool。但可通过以下路径缓解连接压力:
立即学习“PHP免费学习笔记(深入)”;
- 确保
'debug' => false:开启 debug 会禁用连接复用,每次查询都新建 PDO 实例 - 统一使用
Db::name()而非new \think\Db():避免手动实例化绕过连接缓存 - 显式关闭 CLI 场景连接:在命令行脚本末尾加
\think\Db::connect()->close(),防止进程内连接累积 - 读写分离配置
'rw_separate' => true并搭配'master_num'和'slave_no',把读请求分流,降低主库连接竞争
注意:'break_reconnect' => true 只影响断线后是否重试,和连接池无关;它解决的是网络抖动,不是连接资源复用。
Swoole + TP5 协程化改造(唯一可行的池方案)
若你已将 TP5 运行在 Swoole CLI 或 HTTP Server 下(如通过 think-swoole 扩展),才能启用真正意义上的连接池:
- 安装
swoole/database包,并在启动时创建Swoole\Database\PDOPool - 不要把池挂到
Db静态类上,而应封装为服务容器对象(如app('db.pool')),并在协程内按需$pool->get()/$pool->put($conn) - 池参数必须与 MySQL 的
max_connections和 Swoole worker 数匹配:例如worker_num=4、max_connections=200,则池max建议 ≤ 50 - 禁止在池连接上调用
beginTransaction()后不commit()或rollback(),否则该连接会被标记为占用并从池中剔除
示例关键代码片段(非 config 文件修改):
$pool = new \Swoole\Database\PDOPool(
'mysql',
[
'host' => '127.0.0.1',
'dbname' => 'test',
'user' => 'root',
'password' => '',
],
['min' => 5, 'max' => 20]
);
最容易被忽略的瓶颈点
90% 的“连接池失效”问题,其实出在 MySQL 服务端或 PHP-FPM 层:
- 错误
SQLSTATE[HY000] [2002] Connection refused几乎从来不是网络问题,而是SHOW STATUS LIKE 'Threads_connected'已达max_connections上限 - FPM 的
pm.max_children设为 100,每个子进程持有一个未释放的 PDO 连接 → MySQL 端瞬间 100 连接,再加其他服务就爆了 - TP5 在请求结束时自动 close 连接,但前提是没被手动
unset或异常中断 —— 日志里频繁出现PDOException: SQLSTATE[HY000]: General error很可能是连接状态异常未清理
调优顺序永远是:先看 MySQL max_connections 和 wait_timeout,再调 FPM pm.max_children,最后才考虑应用层“模拟池”。



















