pdo::attr_timeout仅控制sql执行超时,非连接超时;连接超时需dsn中设connect_timeout;事务锁等待需mysql端innodb_lock_wait_timeout与php层set_time_limit双重控制;连接池get_timeout仅tp6.1+/think-orm v3.0+生效。

pdo::attr_timeout 控制查询执行卡死,不是连接超时
很多人配了 PDO::ATTR_TIMEOUT 却发现“连不上数据库”时还是卡几十秒,因为这个参数根本不管建连,只管 SQL 执行阶段的等待。它生效的前提是连接已建立,但执行 SELECT 或 UPDATE 时被锁住、或 MySQL 正在忙。
- 必须写在数据库配置的
'params'数组里:'params' => [\PDO::ATTR_TIMEOUT => 3],单位是秒 -
'timeout' => 3或'connect_timeout' => 3这类写法完全无效,PDO 不识别 - TP6.0 及更早版本可能忽略该配置,需确认是否使用 think-orm v3.0+(即 TP6.1+)
- 设为
0表示无限等待——线上环境严禁这么用
DSN 中加 connect_timeout=3 才能防 TCP 建连卡死
首次请求就卡 30 秒?八成是 DNS 解析慢或目标 IP 不可达,而 PHP 默认等满系统级 timeout(Linux 75 秒 / Windows 30 秒)。connect_timeout 是唯一能控制这一步的参数,但它只在 DSN 字符串里生效,且有驱动限制。
- DSN 必须显式包含:
mysql:host=192.168.1.100;port=3306;dbname=test;connect_timeout=3 - host 写域名(如
db.example.com)会引入 DNS 风险,优先改用固定 IP - PHP 8.1+ + TP6.1+ 才真正透传该参数;若用 mysqlnd(PHP 默认驱动),该值可能被忽略
- 验证方式:写个独立脚本,用
mysqli_init()+mysqli_options($link, MYSQLI_OPT_CONNECT_TIMEOUT, 3)测试是否真能在 3 秒内失败
事务中要叠加 set_time_limit 和 innodb_lock_wait_timeout
单纯靠 PDO 超时挡不住锁等待失控。比如两个事务同时更新同一行,PDO::ATTR_TIMEOUT 不起作用,MySQL 会按自己的规则等锁——这时得靠服务端和 PHP 层双重兜底。
- MySQL 端调
innodb_lock_wait_timeout:执行SET SESSION innodb_lock_wait_timeout = 5(单位秒),避免锁争用无限挂住 - PHP 层在事务闭包外调
set_time_limit(10),防非 DB 操作(如 curl、循环)拖垮整个事务 - 别把
set_time_limit()放进Db::transaction(function () { })闭包里——它必须在事务启动前执行才有效 - 如果事务内含 HTTP 请求,
curl_setopt($ch, CURLOPT_TIMEOUT, 8)和curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3)必须都设,缺一不可
连接池 get_timeout 只在 TP6.1+ + think-orm v3.0+ 生效
很多人在 TP5 或 TP6.0 的 config/database.php 里写了 'get_timeout' => 1000,结果毫无反应——因为连接池逻辑根本没加载。这个参数只控制“从已有池子里取连接”的等待上限,不是建连也不是查询超时。
- 仅在 TP6.1+ + think-orm ^3.0 环境下有效;TP5.x / TP6.0 的
'pool'配置完全被忽略 - 必须启用连接池:
'pool' => ['max_active' => 10],不能只写空数组 -
get_timeout单位是毫秒,设为1000表示最多等 1 秒,超时抛think\exception\PDOException - 它只在池满时触发;如果
max_active设得太大,或连接没及时归还(比如漏掉commit()),这个超时根本不会出现
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











