ThinkPHP 无内置数据库连接池,wait_timeout超时需通过mysql.connect_timeout、PDO::ATTR_TIMEOUT和MySQL服务端参数协同控制,pool配置仅在Swoole协程环境下生效。

ThinkPHP 连接池没内置,wait_timeout 超时不是靠“池”解决的
ThinkPHP 6/7 官方不提供数据库连接池功能,所谓“连接池熔断”是误用概念。它底层用的是 PDO,连接由 PHP-FPM 进程生命周期管理,每次请求新建或复用长连接,但不会主动维护连接队列、健康检查或超时抢占。真正影响“等待太久直接失败”的,是 MySQL 服务端的 wait_timeout 和客户端的 PDO 连接参数,不是 ThinkPHP 自己的池逻辑。
实操上要让“获取连接等太久就失败”,得从三处下手:
-
mysql.connect_timeout(PHP 配置):控制 TCP 握手阶段最大等待秒数,建议设为3 - PDO 的
PDO::ATTR_TIMEOUT(ThinkPHP 配置项params.timeout):控制连接建立后执行首个查询前的等待上限,ThinkPHP 默认未启用,需手动加 - MySQL 服务端
wait_timeout(通常 28800 秒):这个值太大,和“快速失败”无关;真正该调小的是connect_timeout和max_connect_errors
在 database.php 中配 params 实现连接级超时
ThinkPHP 的数据库配置里,params 数组会透传给 PDO 构造函数。要让连接尝试在几秒内失败,必须显式设置 PDO::ATTR_TIMEOUT —— 注意这不是 SQL 执行超时,而是连接成功后、发第一条命令前的阻塞等待上限。
示例配置(config/database.php):
立即学习“PHP免费学习笔记(深入)”;
'default' => [
'type' => 'mysql',
'hostname' => '127.0.0.1',
'hostport' => '3306',
'database' => 'test',
'username' => 'root',
'password' => '',
'params' => [
\PDO::ATTR_TIMEOUT => 2, // ⚠️ 关键:单位秒,设 2 表示连接建立后最多等 2 秒就报错
],
],
常见错误现象:SQLSTATE[HY000] [2002] Connection refused 或 SQLSTATE[HY000] [2013] Lost connection to MySQL server during query —— 如果你看到后者且发生在刚连上就查,大概率是这个 timeout 触发了。
为什么 pool 配置项不起作用?
ThinkPHP 文档里提到的 pool 配置(如 max_connections、min_connections)仅适用于 Swoole 环境下的协程连接池,且只在 think-swoole 扩展启用时生效。普通 FPM 模式下,这个配置完全被忽略,代码里也找不到对应实现逻辑。
如果你没跑在 Swoole 上,却在 database.php 里写了 'pool' => ['max_connections' => 10],它不会报错,也不会生效 —— 就是静默丢弃。这也是最容易踩的坑:以为加了就等于有连接池熔断,结果线上 DB 崩了,应用还在死等连接。
验证方式很简单:在控制器里连续执行 Db::query('SELECT SLEEP(5)') 十几次,FPM 下每个请求都会新建连接,根本不会复用或排队。
真要熔断,得自己包一层连接获取逻辑
ThinkPHP 不提供连接获取的钩子,也没 getConnectionWithTimeout() 这种方法。如果业务强依赖“超时即熔断+降级”,只能在调用前自己控制时间:
- 用
pcntl_alarm()(CLI 场景)或stream_set_timeout()(不推荐,PDO 不吃这套)都不靠谱 - 更可行的是封装一个带
microtime(true)计时的tryGetConnection(),在Db::connect()前记录时间,失败后判断耗时,再决定是否抛异常或走缓存降级 - 或者直接改底层:在
think\db\connector\Mysql::connect()方法里加set_time_limit(3),但会污染核心,升级易冲突
复杂点在于:连接失败可能是网络抖动、DB 重启、防火墙拦截,还是 auth 失败?不同原因需要不同响应策略。而 ThinkPHP 的异常类型全都是 think\db\exception\PdoException,没细分,得靠错误信息字符串匹配 Connection refused 或 Too many connections 才能区分。



















