【问题标题】:Long Polling Gives Database Error长轮询导致数据库错误
【发布时间】:2013-08-30 19:33:16
【问题描述】:

我正在尝试构建一个多用户聊天系统,其中数据保存在数据库中并根据请求提取。下面的一段代码只是一个例子,我知道它有很多很好的 SQL 注入,一旦整个事情运行良好,我会改变它们。加上将 php 服务器代码保存在同一个文件中只是为了将代码保持在一个位置,我将在这里解释的问题仍然存在,当服务器代码位于不同的 php 文件中时。

代码运行良好,但问题是我的数据库在一段时间后停止响应。如果有更多用户同时聊天(此脚本的多个实例),那么数据库很快就会停止响应一段时间,并在一段时间后再次开始响应。 请建议我哪里出错了。

<?php
    if($_POST){
        $db=mysqli_connect("localhost","***","****","****");
        if ( isset($_POST['update']) ){
            $q = 0;
            $lasttime = isset($_POST['timestamp']) ? $_POST['timestamp'] : 0;
            while (1){
                sleep(3);
                $mresult = mysqli_query($db,"SELECT * FROM tblchat WHERE msg_datetime > $lasttime");
                $wresult = mysqli_query($db,"SELECT writer_alias FROM tblwriter WHERE writer_isactive=1 AND     (UNIX_TIMESTAMP(NOW())-last_activity)<10");
                if (mysqli_num_rows($mresult)){ $msgs = array(); while ($row = mysqli_fetch_object( $mresult )) { $msgs[] = $row; }     mysqli_free_result($mresult); echo json_encode(array("writers"=>$writers,"msgs"=>$msgs)); flush(); break; }
                if (mysqli_num_rows($wresult)){ $writers = array(); while ($row = mysqli_fetch_object( $wresult )) { $writers[] = $row; }   mysqli_free_result($wresult); echo json_encode(array("writers"=>$writers,"msgs"=>$msgs)); flush(); break; }
                ++$q;
                if ($q>15){ break; }
            }
        }elseif ( isset($_POST['save']) ){
            $msg = isset($_POST['msg']) ? $_POST['msg'] : '';
            if ($msg != ''){
                $from = $_POST["from"];
                $to = $_POST["to"];
                mysqli_query($db,"INSERT INTO tblchat VALUES('".$to."','".$from."','".$msg."','".time()."')");
                echo json_encode(array("success"=>"1"));
                flush();
            }
        }
        mysqli_close($db);
        exit();
    }
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>testing comet</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
  </head>
  <body>
<p>
    <input type="text" name="word" id="word" value="" />
    <input type="button" name="send" value="Send" id="mybutton"/>
</p>
<div id="content"></div>

<script type="text/javascript">
var lastime = 0;
$("#mybutton").click(function(){
    $.post(location.href, {save:"1",from:"1",to:"5",msg:$("#word").val()}, function(data){
        console.log(data);
        $("#word").val("");
    }, "json");
});

$(document).ready( function(){ update(); } );

function update(){
    console.log("update called");
    $.ajax({ type: "POST", url: location.href, data: {update:"1",timestamp:lastime}, success: function(data1){
        console.log(data1);
        lastime = handleDATA(data1.msgs);
    }, dataType: "json", complete: update, timeout: 60000 });
}

function handleDATA (data){
    for(i=0;i<data.length;i++){
        $("#content").append(data[i].msg_from +": "+ data[i].msg+"</br>");
    }
    return data[data.length-1].msg_datetime;
}
</script>

</body>
</html>

【问题讨论】:

  • 您是否检查过如果 $mresult$wresult 由于某种原因都返回 false(或 0 行)会发生什么?它可能会创建一个无限循环。
  • 所以即使ajax请求超时脚本也会继续工作?如果是这样的话,你能建议一种在 30 秒后自愿中断循环的方法吗?
  • 编辑了代码并添加了安全检查,15次尝试后,代码将中断循环并退出。请告诉我它是否安全检查..
  • 关闭,在你检查if($q&gt;15)之前,你应该在它前面的行添加++$q;。你永远不会改变$q
  • 请立即检查编辑。

标签: php mysql ajax database long-polling


【解决方案1】:

虽然这可能是也可能不是绝对的解决方案,但让我们用您的代码修复一些问题(以及一些格式以帮助更好地说明):

旧部分(第 7 - 15 行):

while (1){
    sleep(3);
    $mresult = mysqli_query($db,"SELECT * FROM tblchat WHERE msg_datetime > $lasttime");
    $wresult = mysqli_query($db,"SELECT writer_alias FROM tblwriter WHERE writer_isactive=1 AND     (UNIX_TIMESTAMP(NOW())-last_activity)<10");
    if (mysqli_num_rows($mresult)){ $msgs = array(); while ($row = mysqli_fetch_object( $mresult )) { $msgs[] = $row; }     mysqli_free_result($mresult); echo json_encode(array("writers"=>$writers,"msgs"=>$msgs)); flush(); break; }
    if (mysqli_num_rows($wresult)){ $writers = array(); while ($row = mysqli_fetch_object( $wresult )) { $writers[] = $row; }   mysqli_free_result($wresult); echo json_encode(array("writers"=>$writers,"msgs"=>$msgs)); flush(); break; }
    ++$q;
    if ($q>15){ break; }
}

顶部的新功能:

// This is separate of the while below, put this
// function at top of your script (less code later)

function toArray( myqli_result $result )
{
    while( $row = mysqli_fetch_object( $result ) )
    {
        $array[] = $row;
    }
    mysqli_free_result( $result );

    return $array;
}

新的 While 语句:

//Replacement While Function
while( $q < 15 )
{
    sleep(3);

    $mresult = mysqli_query( $db, "SELECT * FROM tblchat WHERE msg_datetime > $lasttime" );
    $wresult = mysqli_query( $db, "SELECT writer_alias FROM tblwriter WHERE writer_isactive = 1 AND ( UNIX_TIMESTAMP( NOW() ) - last_activity ) < 10" );

    //If you need both results, you must check for both results
    //And do what you need to do, BEFORE break;
    if ( mysqli_num_rows( $mresult ) > 0 && mysqli_num_rows( $wresult ) > 0 )
    {
        $msgs = toArray( $mresult );
        $writers = toArray( $wresult );

        echo json_encode( array( "writers" => $writers, "msgs" => $msgs ) );

        flush();
        break;
    }
    ++$q;
}

简洁的代码让程序员开心,也让以后的调试更容易。

如果您需要两个结果集(看起来确实如此),您将不会像现在的代码那样同时获得这两个结果集,当您获得第一个结果集时,您将摆脱它。这将允许在 json_encode 之前处理两个查询。

这里,toArray( mysqli_result $result ) 是一个函数,它只接受 mysqli_result 对象生成并返回数组,同时释放结果。

如果您发现自己用不同的变量多次编写相同的代码行,您可能希望为它创建一个函数。

【讨论】:

  • 非常感谢杰森。真的很感激。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-18
  • 2014-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多