共享主机下AJAX并发查询触发max_user_connections超限问题咨询
可行解决方案
1. 优先优化:合并批量查询接口(最彻底解决连接超限问题)
你现在每次请求一个子分类就发起一次AJAX,完全可以把当前层级需要查询的所有子分类参数一次性打包传给后端,一次请求拿到全部结果,连接数直接降到1,完全不会触发30的上限。
前端修改:
$.when(info(domain,name)).done((response)=>{ try { layer_info = jQuery.parseJSON(response) }catch (error) { console.log(response) console.log(error) } // 收集所有需要查询的子节点参数 let queryList = [] for (let i = 0; i < layer_info.size; i++) { queryList.push({domain: child_domain, name: child_name}) } // 批量发起一次请求 $.when(batchInfo(queryList)).done((resp)=>{ try { let allChildInfo = jQuery.parseJSON(resp) // 后续渲染逻辑直接用批量返回的结果 } catch (e) { console.log(resp) console.log(e) } }) }) // 新增批量查询方法 function batchInfo(queryArr){ return $.ajax({ url: "info_batch.php", method:"POST", data: {query: JSON.stringify(queryArr)}, dataType: "text", }) }
后端新增批量查询逻辑(info_batch.php):
<?php // 先加缓存逻辑,分类数据基本不变,缓存7天完全没问题 $cacheKey = md5($_POST['query']); $cacheFile = './cache/'.$cacheKey.'.json'; if(file_exists($cacheFile) && (time() - filemtime($cacheFile)) < 86400*7){ echo file_get_contents($cacheFile); exit; } try{ $timezone = "+3:00"; $db=new PDO('mysql:host=localhost;port=3306;dbname=***;charset=utf8','***', '***'); $db->exec("SET time_zone = '{$timezone}'"); $db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); }catch(PDOException $e){ echo $e->getMessage(); exit; } $queryArr = json_decode($_POST['query'], true); $returnData = []; foreach($queryArr as $item){ $name = $item['name']; $domain = $item['domain']; $count_query = $db->prepare("SELECT COUNT(*) FROM table WHERE $domain=?"); $count_query->execute(array($name)); $count_result = $count_query->fetchColumn(); $query = $db->prepare("SELECT * FROM table WHERE $domain=? GROUP BY $sub"); $query->execute(array($name)); $nodes = []; while($results = $query->fetch(PDO::FETCH_ASSOC)){ array_push($nodes,$results); } $returnData[] = [ 'spec_size' => $count_result, "size" => count($nodes), "childs" => $nodes ]; } // 主动关闭数据库连接,立即释放资源 $db = null; $jsonData = json_encode($returnData); // 写入缓存 if(!is_dir('./cache')) mkdir('./cache', 0755, true); file_put_contents($cacheFile, $jsonData); echo $jsonData; ?>
2. 临时方案:前端限制请求并发数
如果暂时不想改接口结构,可以控制前端请求的并发数,限制同时最多20个请求(留10个余量避免其他请求占连接),超过的请求排队等待:
// 并发限制为20 const MAX_CONCURRENT = 20; let current = 0; let queue = []; // 包装请求方法,加入队列逻辑 function requestWithLimit(child_domain, child_name, callback){ if(current < MAX_CONCURRENT){ current++; $.when(info(child_domain, child_name)).done(resp => { callback(resp); current--; if(queue.length > 0){ const next = queue.shift(); requestWithLimit(next.domain, next.name, next.callback); } }) }else{ queue.push({domain: child_domain, name: child_name, callback}); } } // 原循环处替换为队列调用 $.when(info(domain,name)).done((response)=>{ try { layer_info = jQuery.parseJSON(response) }catch (error) { console.log(response) console.log(error) } for (let i = 0; i < layer_info.size; i++) { requestWithLimit(child_domain, child_name, (resp) => { try { child_info = jQuery.parseJSON(resp) } catch (e) { console.log(resp) console.log(e) } }) } })
3. 后端通用优化
即使采用上面的方案,也可以做以下优化进一步降低连接占用:
- 所有接口查询完成后主动执行
$db = null;关闭PDO连接,不要等PHP请求结束自动释放,缩短连接占用时间 - 给原有单查询接口也加上缓存逻辑,相同请求直接读缓存文件,无需连接数据库,完全不占用连接数
- 优化SQL语句,给查询字段添加合适的索引加快查询速度,减少每次请求的连接占用时长
内容的提问来源于stack exchange,提问作者Enes Aytemiz
相关产品推荐
相关产品推荐

