PHP网站遇Too many connections错误:如何正确关闭数据库连接?
我有一个简易PHP网站,每个页面开头都会引入数据库连接脚本,脚本内容如下:
<?php ob_start(); session_start(); // =====MYSQL SETTINGS ===== // $db['db_host'] = "127.0.0.1"; $db['db_user'] = "mysqlusername"; $db['db_pass'] = "mysqlpassword"; $db['db_name'] = "databasename"; // =====END OF MYSQL SETTINGS ===== // foreach($db as $key => $value){ define(strtoupper($key), $value); } $dbconn = mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME); if(!$dbconn){ die("Database connection failed"); } ?>
之后主页面会引入多个实现页面元素的脚本(如菜单、轮播图等),一个页面可能包含15个左右这类文件,典型示例如下:
<?php //show reviews $mainreviewstate = "Y"; //testEnabled Y or N $query = "SELECT Id, Name, Company, Desc FROM tblreviews WHERE Enabled = ? ORDER BY RAND() LIMIT 2"; $stmt = mysqli_stmt_init($dbconn); if(mysqli_stmt_prepare($stmt, $query)){ mysqli_stmt_bind_param($stmt, 's', $mainreviewstate); mysqli_stmt_execute($stmt); mysqli_stmt_store_result($stmt); mysqli_stmt_bind_result($stmt, $Id, $Name, $Company, $Desc); confirmQuery($stmt); while(mysqli_stmt_fetch($stmt)){ // the reviews would show here } //end if stmt while loop mysqli_stmt_free_result($stmt); mysqli_stmt_close($stmt); } //end if stmt query is not empty ?>
每个引入文件都使用首个脚本创建的$dbconn连接执行预处理语句,最后通过mysqli_stmt_close($stmt)关闭语句。
我的网站部署在共享主机上,查看服务器日志发现大量「PHP Warning: mysqli_connect(): (HY000/1040): Too many connections」错误,指向连接脚本中的mysqli_connect。
我原本以为mysqli_stmt_free_result($stmt)和mysqli_stmt_close($stmt)会关闭连接,但现在知道它们仅关闭语句。由于共享主机无法修改MySQL连接数上限,我想咨询:是否需要关闭数据库连接?如果需要,应该在何时何地关闭?比如是每个引入文件执行完语句后关闭,还是在页面加载完成后统一关闭?
是否需要关闭数据库连接?
需要,但更核心的是确保每个请求只创建一个数据库连接——你的当前代码已经做到了这一点(页面开头仅引入一次连接脚本,所有子脚本复用同一个$dbconn),但连接数超限的关键问题通常是连接未及时释放,或是存在请求堆积。
何时何地关闭连接?
统一在页面生命周期结束时关闭
这是最优方案:在所有页面逻辑(包括所有引入的子脚本)执行完成后,调用mysqli_close($dbconn)关闭连接。比如可以在页面的最后位置(所有HTML输出和PHP逻辑完成后)添加这行代码。
原因:复用同一个连接执行所有查询,避免频繁创建/销毁连接的开销,同时确保整个请求结束后立即释放连接,减少MySQL的连接占用。绝对不要在每个子脚本执行完语句后关闭连接
如果在某个子脚本里关闭了$dbconn,后续子脚本再尝试使用这个连接时会直接报错,反而引发更多问题。
额外优化建议
- 禁用持久连接:检查PHP配置中
mysqli.allow_persistent是否开启,共享主机环境下持久连接容易导致僵尸连接无法释放,建议关闭该配置。 - 优化查询效率:慢查询会拉长连接占用时间,加剧连接数不足的问题。比如示例中的
ORDER BY RAND()可通过预生成随机ID等方式优化;给tblreviews的Enabled字段添加索引,提升查询速度。 - 避免重复创建连接:在连接脚本中加入判断,防止因重复引入脚本创建多个连接:
if (!isset($dbconn) || !mysqli_ping($dbconn)) { $dbconn = mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME); if(!$dbconn){ die("Database connection failed"); } }
内容的提问来源于stack exchange,提问作者scim1971

