PHP MySQLi 长连接需在主机名前加 p: 前缀(如 'p:127.0.0.1'),仅面向对象风格有效;PDO 则需设置 PDO::ATTR_PERSISTENT => true,但在 PHP-FPM 下才较可靠,且须注意事务、字符集等上下文污染问题。

PHP MySQLi 长连接怎么开
MySQLi 默认不启用长连接,必须显式传参 MYSQLI_CLIENT_FOUND_ROWS 以外的标志位——关键是加 MYSQLI_CLIENT_INTERACTIVE 或直接用 MYSQLI_OPT_CONNECT_TIMEOUT 配合连接复用逻辑,但更可靠的方式是使用 mysqli::real_connect() 并设置 MYSQLI_CLIENT_COMPRESS | MYSQLI_CLIENT_INTERACTIVE。不过实际中,真正起作用的是在 DSN 或连接参数里带上 p: 前缀(仅限 mysqli 面向对象风格或 mysqlnd 驱动)。
常见错误:以为只要把 mysql_connect() 换成 mysqli_connect() 就自动长连接——其实旧函数已废弃,新函数默认仍是短连接。
- 面向对象写法:用
new mysqli('p:127.0.0.1', ...),主机名前加p:是关键 - 过程式写法不支持
p:前缀,必须改用mysqli_init()+real_connect() -
mysqlnd扩展必须启用(PHP 5.4+ 默认开启),否则p:无效 - 连接池行为由 PHP-FPM 进程生命周期决定,不是“永久”,而是进程内复用
PDO MySQL 长连接真的能用吗
PDO 的 PDO::ATTR_PERSISTENT => true 看似简单,但实际效果受限于底层驱动和 Web SAPI 环境。在 CLI 下几乎无效,在 Apache mod_php 下表现不稳定,在 PHP-FPM 下才较可靠——因为连接复用依赖于 worker 进程的存活时间。
容易踩的坑:PDO::ATTR_PERSISTENT 不会自动清理事务、临时表、用户变量等上下文状态,上一个请求留下的 SET NAMES utf8mb4 或未提交事务可能污染下一个请求。
立即学习“PHP免费学习笔记(深入)”;
- 必须在每次请求开始时显式调用
$pdo->beginTransaction()/$pdo->rollBack()或执行RESET QUERY CACHE类语句(不推荐) - 避免在持久连接上使用
USE DB_NAME切库,应统一用带库名的表引用(如db1.users) - 连接超时由 MySQL 的
wait_timeout控制,PDO 层无法绕过,需确保该值 ≥ PHP-FPMmax_request - 调试时可用
SHOW PROCESSLIST观察Command列是否为Sleep且Time持续增长
为什么开了长连接还是频繁重连
根本原因往往不在 PHP 配置,而在 MySQL 服务端或中间件限制。最常见的是:PHP-FPM 子进程被 pm.max_requests 强制回收、MySQL 的 wait_timeout(默认 28800 秒)先于 PHP 进程失效、或负载均衡器(如 Nginx)主动断开空闲连接。
- 检查 PHP-FPM 日志是否有
child exited记录,确认是否因max_requests触发重启 - 执行
SELECT @@wait_timeout, @@interactive_timeout,二者都需调大(例如设为 3600) - Nginx 的
proxy_read_timeout和keepalive_timeout必须 ≥ MySQLwait_timeout - 某些云数据库(如阿里云 RDS)会强制 kill 空闲连接,需在应用层加心跳(如定时执行
SELECT 1)
长连接要不要手动 close()
不需要,也不应该调用 mysqli_close() 或 $pdo = null。长连接的设计本意就是让连接留在进程内存中复用;手动关闭反而触发重建,失去意义。PHP 请求结束时,若启用了持久化机制,连接会被归还到连接池而非销毁。
但要注意:如果代码中存在 unset($mysqli) 或异常提前退出未捕获,可能导致连接句柄泄露(尤其在 PHP-FPM 中表现为 Too many connections 错误)。
- 永远不要在请求末尾写
mysqli_close($link) - 使用 try/finally 确保事务回滚,但不要在里面关连接
- 监控 MySQL 的
Threads_connected和Threads_created,比值持续接近 1 表示长连接生效 - 真正该关的是非持久连接(如 CLI 脚本、队列任务),否则可能耗尽 MySQL 连接数











