mysqli_close()仅对普通连接有效,对持久连接(如mysqli_pconnect()或PDO启用ATTR_PERSISTENT)无效,此时仅归还连接池;真正释放需配合清理结果集、语句对象及置空连接。

mysqli_close() 不一定真断开,PDO 里设 $pdo = null 才算真正释放。是否“断开”,取决于你用的是普通连接还是持久连接。
mysqli_close() 在什么情况下不生效
调用 mysqli_close($conn) 后连接还“活着”,大概率是因为用了持久连接——比如代码里写了 mysqli_pconnect(),或底层驱动(如 mysqli 或 PDO)启用了持久化配置。
- 普通连接(
mysqli_connect()):调用mysqli_close()会真正关闭 TCP 连接 - 持久连接(
mysqli_pconnect()或 PDO 中设置了PDO::ATTR_PERSISTENT => true):mysqli_close()只是把连接归还池子,下次mysqli_connect()还可能复用它 - CLI 脚本中尤其要注意:没显式关闭 + 持久连接 = 连接长期滞留,可能触发 MySQL 的
wait_timeout被服务端主动踢掉,后续操作报MySQL server has gone away
PDO 断开连接的唯一可靠写法
PDO 没有 close() 方法,官方文档明确说“销毁对象即断开”。但光写 unset($pdo) 不够稳,因为可能还有残留引用(比如 PDOStatement 对象仍持有着 $pdo 的引用)。
- 必须先置空语句对象:
$stmt = null(不是unset($stmt),更明确) - 再置空连接对象:
$pdo = null - 如果用了事务,务必在
$pdo = null前执行$pdo->rollback()或$pdo->commit(),否则连接可能卡在未决事务状态 - 不要依赖析构函数或脚本结束自动清理——CLI 长任务、Swoole 等常驻进程下,PHP 不会自动回收
结果集和预处理语句的资源泄漏点
很多人只关连接,却忘了释放查询结果和语句句柄,内存涨得飞快,尤其是导出百万行数据时。
-
mysqli_query()返回mysqli_result对象后,必须调用mysqli_free_result($result),再unset($result)——顺序不能反,否则 PHP 引用计数不降,内存不释放 - 用
mysqli_fetch_all(MYSQLI_ASSOC)一次性取完?那不用mysqli_free_result(),因为结果已转为数组,原资源自动释放 - PDO 中
$stmt->fetch()不持有底层句柄,但$stmt本身是资源对象,循环中反复$pdo->prepare($sql)而不复用,会导致句柄堆积;应提前prepare,循环只execute()
流式查询(unbuffered)下不遍历完就断开的后果
当 PDO 设置了 PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false(即流式查询),MySQL 不缓存整张结果集,而是一边查一边吐。这时候如果没读完就执行 $pdo = null,后续任何新查询都会失败,并抛出错误:Cannot execute queries while other unbuffered queries are active。
立即学习“PHP免费学习笔记(深入)”;
- 流式查询适合超大结果集(如日志分析),但代价是必须完整遍历,不能中途
break或return - 若逻辑上确实需要中断,应在中断前调用
$stmt->closeCursor()(PDO)或mysqli_free_result($result)(MySQLi) - 默认是缓冲查询(buffered),所以这个坑多数人踩不到——除非你特意关了它



















