MySQLi持久连接仅支持过程式mysqli_connect()加p:前缀,面向对象new mysqli()完全忽略p:前缀;持久连接需DSN完全一致、受wait_timeout和PHP-FPM生命周期约束,且存在事务/变量残留风险。

MySQLi 持久连接必须用 mysqli_connect(),不能用面向对象构造
PHP 中只有过程式调用 mysqli_connect() 支持通过主机名前加 p: 启用持久连接;面向对象方式(new mysqli())**完全忽略 p: 前缀**,哪怕你写成 new mysqli('p:localhost', ...),它也只当普通连接处理,且不会报错——这是最常被踩的坑。
原因在于:持久连接池由 PHP 内核在 mysqli_connect() 底层管理,而 mysqli 类构造函数绕过了该机制,直接走新建 socket 流程。
- ✅ 正确写法:
mysqli_connect('p:localhost', 'user', 'pass', 'db') - ❌ 无效写法:
new mysqli('p:localhost', 'user', 'pass', 'db') - ⚠️ 注意:即使使用
mysqli_real_connect(),也必须配合已初始化的持久资源句柄,不能单独靠前缀生效
p: 前缀只影响连接复用,不改变超时或连接数限制
加了 p: 不代表连接永不关闭,也不代表能突破 mysqli.max_persistent 或 mysqlnd.max_links 配置。持久连接仍受 PHP-FPM worker 生命周期约束:一个请求结束后,连接会归还到当前进程的持久池中,等待下一次同进程内的相同 DSN 请求复用。
- 若 FPM 设置
pm.max_requests = 500,则每个 worker 最多复用 500 次,之后进程重启,所有持久连接释放 -
wait_timeout(MySQL 侧)依然生效:空闲超过该值的持久连接会被 MySQL 主动断开,下次复用时mysqli会自动重连(但会抛出警告,需捕获mysqli_connect_errno()判断) - DSN 必须**完全一致**才复用:主机、端口、用户名、密码、数据库名、socket 路径缺一不可;
p:127.0.0.1和p:localhost被视为两个不同池
验证是否真的用了持久连接的两种可靠方法
仅看连接是否“快”或“不断开”不作数。真正确认得查底层状态:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 在 MySQL 服务端执行
SHOW PROCESSLIST,观察连接的Command列是否长期显示为Sleep,且Time值持续增长(普通连接通常几秒内断开) - 在 PHP 中调用
mysqli_get_client_info()确认是 mysqlnd(非 libmysql),然后检查mysqli_get_server_info($link)返回的连接 ID 是否在多次请求中重复出现(同一 FPM worker 下) - ⚠️ 错误验证方式:用
mysqli_ping()返回 true 就认为是持久连接——普通连接刚建立时也返回 true
生产环境慎用持久连接的三个现实约束
持久连接不是性能银弹,反而容易在特定场景引发问题:
- 事务未提交或锁未释放时连接归池,下一个复用者可能意外继承脏状态(如
SELECT ... FOR UPDATE持有行锁后脚本退出,连接被复用时锁还在) - 连接变量(如
SET NAMES utf8mb4、sql_mode)不会自动重置,复用者可能拿到前任留下的非预期设置 - 连接池大小失控:如果应用大量使用不同 DSN(比如按用户分库拼接 host),会导致内存中堆积大量闲置连接,最终触发 MySQL 的
max_connections限制
这些细节往往在压测后期才暴露,且错误表现分散——比如偶发的字符乱码、死锁、Too many connections 报错。用之前务必确认你的业务模型能干净地收尾每次数据库交互。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










