本文目录导读:

在 PHP 中,持久连接(Persistent Connection)主要应用于数据库连接场景,它的核心思想是:在一次请求结束后,不关闭与数据库的连接,而是将其放入连接池中,供后续请求复用,从而避免每次请求都重新建立 TCP 连接的开销。
PHP 的持久连接机制与 Java 或 Python 等常驻内存的语言不同——PHP 本身是“请求-响应”模式,每个请求结束后内存会释放,PHP 的持久连接通常由扩展内部通过进程池或连接池实现。
常见数据库的持久连接实现
1 MySQL(mysqli / PDO)
mysqli 示例:
// 在主机名前加 "p:" 前缀
$db = new mysqli('p:localhost', 'user', 'pass', 'dbname');
PDO 示例:
$db = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass', [
PDO::ATTR_PERSISTENT => true
]);
核心逻辑:
- 连接关闭时不会真正断开,而是返回连接池。
- 同一个
host:port:user的后续请求会复用该连接。 - 连接失效时(如 MySQL 超时关闭),扩展会自动清理。
⚠️ 注意事项:
- 不要混用持久连接和非持久连接(可能导致连接泄漏)。
- 使用持久连接时,必须显式处理事务回滚,否则残留事务会影响下一个请求。
- PHP-FPM 模式下,持久连接会关联到进程:同一 worker 进程的多个请求可复用连接。
2 PostgreSQL(pgsql / PDO_PGSQL)
pgsql 扩展:
$conn = pg_pconnect("host=localhost dbname=test user=user password=pass");
或使用 pg_connect 带 PGSQL_CONNECT_FORCE_NEW 常量。
PDO_PGSQL:
$db = new PDO('pgsql:host=localhost;dbname=test', 'user', 'pass', [
PDO::ATTR_PERSISTENT => true
]);
3 Redis / Memcached(非数据库持久连接)
- Redis:
phpredis扩展支持pconnect()方法,连接在进程生命周期内保持。 - Memcached:构造函数中指定
persistent_id实现复用。
PHP 持久连接的底层原理
PHP 本身不是常驻内存的,但 PHP 扩展(如 mysqli、pdo_mysql)可以在内部维护连接池,当启用 p: 或 PDO::ATTR_PERSISTENT 时:
- 请求开始 → 检查连接池中是否有匹配的空闲连接(匹配条件:主机、端口、用户名、数据库名)。
- 有连接 → 复用(但需验证连接是否有效,无效则重建)。
- 无连接 → 创建新连接并加入池。
- 请求结束 → 不调用
mysql_close()或pg_close(),而是将连接标记为空闲,放回池中。 - 下次同一进程的请求 → 从池中取出连接(跳过 TCP 握手)。
注意:连接池属于 PHP 进程级别,而非跨进程共享。
- 使用
mod_php(Apache 模块)时,连接池随 Apache 子进程存活。 - 使用
PHP-FPM时,连接池随 FPM worker 进程存活。
何时使用持久连接?
✅ 推荐场景
- 高并发、短连接频繁建立(如大量 API 请求)。
- 数据库连接开销大(如使用 SSL、高延迟网络)。
- PHP-FPM 工作进程数相对稳定(如 50~200 个进程)。
❌ 不建议的场景
- 每个用户使用不同数据库账号(连接池无法复用)。
- 数据库有连接数限制(持久连接会占用更多连接)。
- 使用事务时未显式回滚(残留锁或事务影响后续请求)。
- 使用长连接池管理工具(如 pgbouncer、ProxySQL) 时,应用层持久连接可能无意义。
常见坑与解决方案
1 连接死锁或断开
- 现象:MySQL
wait_timeout或interactive_timeout后,PHP 进程尝试复用已断开的连接。 - 解决:启用
PDO::ATTR_PERSISTENT时,PDO 内部会执行SET AUTOCOMMIT=1和ping()检测,无效则重建。
2 事务残留
- 问题:上一个请求未提交事务,下一个请求继续使用该连接,导致脏数据。
- 解决:在请求结束时主动回滚事务。
3 连接数膨胀
- 问题:每个 PHP-FPM worker 进程都持有独立连接,总连接数 = 进程数 × 每进程连接数。
- 解决:限制 FPM
pm.max_children,或使用连接池中间件(如 ProxySQL)。
持久连接的真实性能收益
| 场景 | 非持久连接 | 持久连接 | 收益 |
|---|---|---|---|
| 每次请求只执行一次简单查询 | ~2ms 建立 + 0.1ms 执行 | 1ms 执行 | 显著 |
| 每次请求执行 10 次复杂查询 | 2ms 建立 + 50ms 执行 | 0ms 建立 + 50ms 执行 | 4% |
| 数据库在本地(Unix Socket) | 1ms 建立 | 0ms 建立 | 可忽略 |
当网络延迟较高(如云服务器跨可用区、外网数据库)或查询极短时,收益最明显。
- 持久连接 ≠ 连接池:PHP 持久连接本质是进程级连接复用,而非真正跨进程的共享连接池。
- 使用方式:加
p:前缀(mysqli)或PDO::ATTR_PERSISTENT(PDO)。 - 核心注意:事务清理、连接有效性验证、连接数控制。
- 替代方案:如果连接池管理复杂度高,考虑使用数据库中间件(如 ProxySQL、PgBouncer)。
如果需要进一步了解特定场景(如 Laravel/Symfony 中的持久连接配置),可以告诉我具体框架,我可以给出更详细的代码示例。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播