Think如何做数据库连接池连接获取超时 Think等待连接最长时限设置操作最佳践|Duuu笔记
面向高级开发者的PHP指南,涵盖
ThinkPHP 仅在6.1+配合think-orm v3.0+才支持连接池,需配置pool项中的get_timeout控制获取超时;TP5.x和TP6.0不支持,pool配置无效;超时异常为think\db\exception\PDOException,常因未达池满或被重试/异常处理器掩盖。
ThinkPHP 连接池没生效?先确认你用的是哪个版本
ThinkPHP 本身不内置数据库连接池,所谓“连接池”是靠底层 PDO 连接复用 + 连接管理器实现的模拟效果,仅在
think-orm
v3.0+(即 ThinkPHP 6.1+ 配合独立 ORM)中通过
pool
配置项提供有限支持。TP5.x 和 TP6.0 默认压根没有连接池逻辑,
pool
配置会被忽略。
常见错误现象:
pool
配置写了但连接数始终不复用、监控显示频繁新建连接、
show processlist
看到大量
Sleep
状态连接却没被回收。
TP5.1/5.2:无连接池,
'pool' => [...]
是无效配置,删掉避免误导
TP6.0:仍不支持,ORM 是 v2.x,
pool
不识别
TP6.1+ + think-orm ^3.0:才真正支持,且必须使用
ConnectionPool
类或开启
'pool' => ['max_active' => 20]
如何启用 think-orm v3 的连接池并设置获取超时
超时控制分两层:连接建立超时(PDO 层)、连接从池中获取超时(池管理层)。后者才是你标题里说的“获取超时”,对应
get_timeout
参数。
配置示例(
config/database.php
):
“
PHP免费学习笔记(深入)
”;
Action Figure AI
借助Action Figure AI的先进技术,瞬间将照片转化为定制动作人偶。
下载
'mysql' => [
'type' => 'mysql',
'hostname' => '127.0.0.1',
'database' => 'test',
'username' => 'root',
'password' => '',
'hostport' => '3306',
'charset' => 'utf8mb4',
'debug' => false,
'deploy' => 0,
'rw_separate' => false,
'master_num' => 1,
'slave_no' => '',
'pool' => [
'max_active' => 10, // 最大活跃连接数
'min_idle' => 2, // 最小空闲连接数
'max_wait' => 3000, // 池满时最大等待毫秒数(关键!)
'get_timeout' => 1000, // 获取连接超时时间(毫秒),超时抛出 Think\Exception\PDOException
'time_between_eviction_runs_millis' => 60000,
],
],
get_timeout
是你要设的“等待连接最长时限”,单位毫秒,设为
1000
表示等 1 秒就放弃
max_wait
是池子满时,新请求在队列里最多等多久——它和
get_timeout
是两个不同阶段的超时,别混用
若不配
pool
,所有连接走默认单例模式,
get_timeout
完全不生效
为什么设置了 get_timeout 却没抛异常?
最常见原因是:你没触发“池满等待”场景,或者异常被上层吞了。ThinkPHP 的查询方法(如
Db::table()->select()
)默认会静默重试一次,掩盖了首次获取失败。
检查是否真达到
max_active
:用
SHOW STATUS LIKE 'Threads_connected';
对比实际连接数
手动测试获取逻辑,绕过 ORM 封装:
$conn = Db::connect('mysql')->getPool()->getConnection();
,再主动调用
getConnection()
触发超时
注意错误类型:超时抛的是
think\db\exception\PDOException
,不是
think\Exception
,日志里搜不到可能因为异常类名写错了
TP6.1+ 中,若启用了
break_reconnect
或自定义了
ExceptionHandler
,可能把该异常转成 HTTP 500 而没打日志
连接池 + 超时在高并发下的真实表现
它不是银弹。连接池能缓解短时并发压力,但无法解决慢查询堆积、事务未提交导致连接长期占用等问题。
一个未提交的事务会让连接一直卡在池中,后续请求即使
get_timeout=100
也会等满 100ms 后失败——这不是配置问题,是业务代码缺陷
min_idle
设太高会导致空闲连接常驻,MySQL 的
wait_timeout
可能先把它断开,下次取用时报
MySQL server has gone away
容器环境(如 Docker)中,DNS 解析慢会导致
get_timeout
在连接建立前就触发,建议加
'params' => [PDO::ATTR_TIMEOUT => 2]
控制底层 PDO 建连超时
连接池的“超时”只管等不等得到连接,不管连上了干啥。业务里有没有 long query、有没有忘关事务、有没有循环查库,这些才是压垮数据库的真正开关。
