发布于2026-07-09 阅读(0)
扫一扫,手机访问
先说说很多开发者容易踩的一个坑:很多人以为 ThinkPHP 里把 'persistent' => true 一开,就算用上数据库连接池了。实际上,这跟真正的连接池差了十万八千里。所谓“持久连接”,仅仅是 PDO 层在单个进程内部复用同一个底层 socket,既没有连接数限制,也没有排队等待机制,更谈不上健康检查和跨请求复用。高并发下,Too many connections 或者 MySQL has gone away 这类报错依旧会频繁出现。要想真正实现池化,必须换环境、换组件。

开启持久连接后,每次调用 Db::connect(),TP 依然会新建一个 PDO 实例——哪怕底层 socket 可能被复用。关键是它不共享、不限流、也不回收空闲连接。具体问题出在哪?
max_connections 是全局上限,但 TP 根本不感知实际创建了多少连接,也没法控制。wait_timeout 决定(默认 8 小时),可 PHP 请求通常几秒就结束了。下次复用的时候,很可能连接早就断开了,直接报 MySQL server has gone away。缺一不可:
Db::pool() 调用全部无效,别费劲。db_pool 功能。原生 TP 的 database.php 里加任何 pool 字段都是摆设。怎么验证是否生效?在控制器里打印 get_class(Db::pool()),如果返回的是 think\swoole\pool\DatabasePool,说明走对了;如果还是 think\db\Connection,那就根本没进池子。
即使启用了连接池,大量代码仍然会绕过它走传统连接,这点特别容易忽略:
Db::table()、Db::name() —— 默认用的还是非池化连接。Db::transaction() —— 默认也不走池,必须显式写成 Db::pool()->transaction()。UserModel::find())—— 默认绑定的是普通 Db 实例,需要手动注入池化连接,或者重写模型的 db() 方法。Db::connect('sla ve') 不等于 Db::pool()->connect('sla ve'),只有后者才进池。安全写法其实很简单:Db::pool()->table('user')->where('id', 1)->find(),千万别省略 pool() 这一步。
配置在 config/swoole.php 的 db_pool 节点下,有几个参数特别容易配错:
max_active => 10:表示单个 Worker 进程最多持有 10 条连接。如果 swoole.server.worker_num 设为 4,那整个服务最多就是 40 条连接。但 MySQL 的 max_connections 如果只设了 30,多余请求就会被直接拒绝。wait_timeout => 2000:协程等待空闲连接的超时时间(毫秒)。设太小(比如 100)会导致大量 PoolTimeoutException;设太大(比如 10000)又会让慢请求拖垮整体响应。idle_timeout => 60:空闲连接存活秒数。它不影响创建速率,只决定“冷连接”多久被回收。真正控制连接创建速度的,是 max_active。还有一个最容易被忽略的点:Swoole 每个 Worker 进程都有独立的连接池,预热必须在 WorkerStart 事件里做,否则只有第一个 Worker 有连接,其余 Worker 在首次请求时仍然要等待新建连接,池化的优势就大打折扣了。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8