You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL通用SELECT查询类执行触发无限循环问题排查

问题分析与解决方案

核心问题排查

你遇到的无限循环+重复日志问题,主要有以下几个根源,结合代码逐一分析:

1. 调用代码的语法错误

你贴出的调用代码存在语法错误:末尾多了一个闭合括号)和左大括号{,这会导致PHP解析失败。如果服务器配置了错误页面重定向到原脚本,就会触发无限请求循环,每次请求都会执行Select方法并写入日志。

修正后的调用代码:

$obj_artikel_startseite = new DbQuery();
$result = $obj_artikel_startseite->Select(
    array("*"), 
    "psartikel", 
    array(
        array("link" => "AND", "key" => "status", "value" => "freigeschaltet", "operand" => "="), 
        array("link" => "OR", "key" => "status", "value" => "reserviert", "operand" => "=")
    ), 
    array("id"), 
    "DESC", 
    0, 
    3
);

2. LIMIT条件判断逻辑错误

你的LIMIT判断用了$limitIndex != null && $limitLength != null,但在PHP的松散比较中,0 != null会返回false(因为0和null松散相等),导致传入的0,3无法触发LIMIT子句。这虽然不是无限循环的直接原因,但会导致查询结果不符合预期。

修正为严格的非空判断:

if (!is_null($limitIndex) && !is_null($limitLength)) {
    // 强制转成整数,避免SQL注入风险
    $statement .= " LIMIT " . (int)$limitIndex . "," . (int)$limitLength;
}

3. 异常未捕获导致的递归循环

如果你的DatabaseFactory返回的PDO对象开启了PDO::ERRMODE_EXCEPTION错误模式,$query->execute()执行失败时会抛出异常。若全局异常处理逻辑中再次调用了Select方法,就会触发无限递归。

添加异常捕获逻辑,避免循环:

// 在$query->execute()前后添加try-catch
try {
    $query->execute();
} catch(PDOException $e) {
    // 单独记录错误日志,避免干扰正常日志
    $errorLog = date("Y-m-d H:i:s", time()) . " => Execute Error: " . $e->getMessage() . "\n";
    file_put_contents($_SERVER["DOCUMENT_ROOT"] . '/../db-error.log', $errorLog, FILE_APPEND);
    return false;
}

4. 日志写入的性能与锁问题

你当前的日志写入方式是先读取整个文件再追加,高并发(或循环请求)下容易出现文件锁冲突,也会加剧性能问题。改用FILE_APPEND模式直接追加:

// 替换原日志写入代码
$logContent = date("Y-m-d H:i:s", time()) . " => Statement: " . $statement . "\n";
file_put_contents($_SERVER["DOCUMENT_ROOT"] . '/../db.log', $logContent, FILE_APPEND);

// 绑定值的日志同理
$bindLog = date("Y-m-d H:i:s", time()) . " => BindValue: " . $keystring . " -> " . trim(strip_tags($whereClause['value'])) . "\n";
file_put_contents($_SERVER["DOCUMENT_ROOT"] . '/../db.log', $bindLog, FILE_APPEND);

最终修正后的Select方法代码

public function Select($keys = array("*"), $table, $whereClauseArray = null, $orderValues = null, $orderDirection = null, $limitIndex = null, $limitLength = null)
{
    $statement = "SELECT " . implode(',', $keys) . " FROM " . $table;
    
    // 处理WHERE子句
    if (!empty($whereClauseArray)) {
        $whereClauseString = " WHERE ";
        $i = 0;
        foreach ($whereClauseArray as $whereClause) {
            if ($i > 0) {
                $whereClauseString .= " " . $whereClause['link'] . " ";
            }
            $whereClauseString .= $whereClause['key'] . " " . $whereClause['operand'] . " :" . $whereClause['key'] . "_" . $i;
            $i++;
        }
        $statement .= $whereClauseString;
    }
    
    // 处理ORDER BY子句(简化写法)
    if (!empty($orderValues)) {
        $orderClause = " ORDER BY " . implode(', ', $orderValues);
        $statement .= $orderClause . " " . $orderDirection;
    }
    
    // 处理LIMIT子句
    if (!is_null($limitIndex) && !is_null($limitLength)) {
        $statement .= " LIMIT " . (int)$limitIndex . "," . (int)$limitLength;
    }

    $query = $this->database->prepare($statement . ";");
    
    // 写入SQL语句日志
    $logContent = date("Y-m-d H:i:s", time()) . " => Statement: " . $statement . "\n";
    file_put_contents($_SERVER["DOCUMENT_ROOT"] . '/../db.log', $logContent, FILE_APPEND);
    
    // 绑定参数(先判断非空)
    if (!empty($whereClauseArray)) {
        $j = 0;
        foreach ($whereClauseArray as $whereClause) {
            $keystring = ":" . $whereClause['key'] . "_" . $j;
            $bindValue = trim(strip_tags($whereClause['value']));
            $query->bindValue($keystring, $bindValue);
            
            // 绑定日志
            $bindLog = date("Y-m-d H:i:s", time()) . " => BindValue: " . $keystring . " -> " . $bindValue . "\n";
            file_put_contents($_SERVER["DOCUMENT_ROOT"] . '/../db.log', $bindLog, FILE_APPEND);
            $j++;
        }
    }

    // 执行查询并捕获异常
    try {
        $query->execute();
    } catch(PDOException $e) {
        $errorLog = date("Y-m-d H:i:s", time()) . " => Execute Error: " . $e->getMessage() . "\n";
        file_put_contents($_SERVER["DOCUMENT_ROOT"] . '/../db-error.log', $errorLog, FILE_APPEND);
        return false;
    }

    // 返回结果(修正count(*)的判断逻辑)
    if ($keys === array("count(*)")) {
        return $query->fetchColumn(0);
    } else {
        return $query->fetchAll();
    }
}

注:原代码中if ($keys === "count(*)")的判断逻辑错误,因为$keys默认是数组类型,需改为判断$keys === array("count(*)")才能触发fetchColumn逻辑。

内容的提问来源于stack exchange,提问作者meDom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 03:25:31