必须显式释放:select 用 mysqli_free_result(),预处理语句用 $stmt->close(),连接用 $mysqli->close();否则易致连接耗尽或句柄泄漏。

PHP执行SQL语句后不释放资源,轻则内存缓慢增长、连接数耗尽,重则在高并发下触发 mysqli 或 PDO 的句柄泄漏错误(如 Too many connections 或 MySQL server has gone away)。关键不是“要不要释放”,而是“在哪一步、用什么方式、针对哪类资源”释放——不同执行路径对应不同释放动作。
mysqli_query() 执行后如何释放结果集
用 mysqli_query() 执行 SELECT 时,返回的是 mysqli_result 对象,它占用内存并持有结果集缓冲区。不显式释放,该结果集会持续驻留直到脚本结束或变量被覆盖。
-
mysqli_free_result($result)是标准做法;即使后续不再使用$result,也建议主动调用 - 若已用
mysqli_fetch_all()或循环取完所有行,mysqli_free_result()仍有必要——它释放底层 C 层的 result set 结构,而不仅仅是 PHP 变量引用 - 对
INSERT/UPDATE/DELETE等非查询语句,mysqli_query()返回布尔值,无需mysqli_free_result()
mysqli_prepare() 预处理语句必须调用 close()
预处理语句(mysqli_prepare())生成的 mysqli_stmt 对象是独立资源,和连接、结果集都不同。它不会随脚本结束自动销毁,尤其在长生命周期的 CLI 脚本或常驻进程里极易堆积。
- 每次
$stmt->execute()后,若不再复用该语句,应立即调用$stmt->close() - 若语句只执行一次(比如单次插入),
close()应放在execute()和get_result()(如有)之后 - 漏掉
close()不会立刻报错,但反复调用prepare()会持续消耗 MySQL 的prepared_stmt_count,达到上限(默认 16382)后新prepare()将失败,错误信息类似MySQL server has gone away
PDO 中 fetch() 后是否需要手动释放
PDO 的行为更隐式,但也更易误判。PDOStatement 对象本身不强制要求 close,但资源清理时机依赖使用方式:
- 用
$pdo->query($sql)+fetch():无需额外操作,PDO 内部会在语句对象销毁时自动清理;但若长期持有$stmt变量(如作为类属性),应设为null或调用$stmt = null触发析构 - 用
$pdo->prepare($sql):强烈建议执行完后调用$stmt->closeCursor(),尤其当语句可能返回多结果集、或需复用同一连接执行其他语句时——它解除语句与结果集的绑定,释放读取锁和缓冲区 -
closeCursor()不等于关闭连接,也不影响事务状态;但它能防止 “Commands out of sync” 类错误,特别是在一个连接上连续执行多个SELECT时
连接本身何时关闭、为什么不能省略
无论是 mysqli 还是 PDO,连接资源(mysqli 对象或 PDO 实例)在脚本结束时会自动关闭,但显式关闭仍是必要习惯:
-
$mysqli->close()或$pdo = null应放在所有数据库操作完成之后,尤其是连接由函数返回、或在循环中反复创建时 - 不关闭连接最直接的后果是连接池耗尽:MySQL 默认
max_connections=151,PHP-FPM 子进程复用连接时若未释放,很快就会卡在Waiting for table metadata lock或拒绝新连接 - 注意:
mysqli_close()不能用于mysqli_connect()创建的面向对象实例——必须调用实例方法$mysqli->close();而mysqli_close($mysqli)仅适用于过程式风格
最容易被忽略的是预处理语句的 close() 和 PDO 的 closeCursor():它们不报错、不中断逻辑,却在后台悄悄累积资源压力。线上服务跑几天后响应变慢、连接数异常升高,十有八九是这两处没做。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











