【问题标题】:Retry on database exception using php使用 php 重试数据库异常
【发布时间】:2015-09-02 08:03:08
【问题描述】:

我一直在处理 php - mysqli 引发的异常,并在下面创建了这个 sn-p,它试图检查几次以查看临时故障是否导致数据库失败。如果是这样,它会尝试恢复。如果不能,则退出/结束。

现在虽然逻辑没问题,但我不知道为什么 echo 语句没有按应有的规律间隔出现。仅在最后(取决于 findMail() 函数中抛出异常的方式),输出才会被正确地吐出。 throw new exception 行可以更改为始终失败或最后一次通过。它被设置为通过 sn-p 中的最后一轮。如果有人能指出我为什么 echo 没有按间隔显示输出,那就太好了。

此外,我不确定这在生产中是好主意还是坏主意。非常欢迎对此提供任何反馈。谢谢大家。

代码片段:

<?php
$host        = 'localhost';
$user        = 'root';
$password    = '';
$database    = 'test';

// OPEN A CONNECTION TO THE DATA BASE SERVER AND SELECT THE DB

try
{
    $con = new mysqli($host,$user,$password,$database);
    if($con->connect_error)
    {
        throw new Exception("Goof Up");
    }   
    mysqli_set_charset($con, "utf8"); 
}
catch(Exception $e)
{
    echo $e->getMessage();
    exit;
}

// All well so far 

$cnt = 0;
if(findMail($con,$cnt)) echo "<br> Hurray !!";

function findMail($con,$cnt)
{
    try
    {   
        echo $cnt++."<br>";
        $query = "SELECT name, email from users";
        $stmt=$con->prepare($query);
        if($cnt < 3 ) throw new exception($cnt);
        if($stmt->execute())    
        {   
            $stmt->bind_result($name, $email);
            while ($stmt->fetch())
                {
                    $email = htmlspecialchars($email);
                    $name = htmlspecialchars($name);
                    echo $name.' ---- '.$email.'<br>'; 
                }       
        }
    }
    catch(Exception $e)
    {
        $cnt = (int)($e->getMessage());
//      echo $cnt;
        if($cnt === 4) { echo "Ending"; exit();} 
        sleep(5);
        findMail($con,$cnt);
    }   
    return true;
}
?>

【问题讨论】:

  • 能否将输出添加到您的代码 sn-p 中?
  • 确定输出是 0 1 2 我得到了名字 --- 电子邮件和“万岁!” .输出正确且符合预期。只是应该以 5 秒的间隔回显 0、1、2 等,但事实并非如此。整个输出发生在 20 秒间隔结束时,或者取决于
    if($cnt 
  • 如何使用flush() / ob_flush() - 这样做的原因是什么:if($cnt &lt; 3 ) throw new exception($cnt);?
  • 是的,我尝试了函数 flush() 但这也不起作用。
     if ($cnt 的原因是模拟失败 3 次,最后让查询第 4 次成功。只是为了检查代码是否会根据需要处理意外查询,即不会立即终止程序,而是在退出之前尝试几次($cnt)。
  • 这是我根据您的建议修改的文件的链接。 codepen.io/ajoo/pen/OVjdqj.html 链接>。请注意,errScript.php 只包含一行代码。 '
     if(findMail($con,$cnt)) echo "万岁!!" 
    '

标签: php exception mysqli


【解决方案1】:

将此 PHP 脚本与 sleep(X) 一起使用可能会导致用户等待其完成(成功与否)。

我建议通过 AJAX 调用脚本(例如 jQuery.ajax([...])),这样前端就不会被阻塞。

已更新 - 改用 ajax 的示例

文件:test.php

<?php
// verify if this is an ajax request (if, so exit the script before out)
if(isset($_GET['ajax'])) {

    $host        = 'localhost';
    $user        = 'root';
    $password    = '';
    $database    = 'test';

    // return result being parsed by JS through json_encode
    $result = array('data' => null, "error" => false);

   /**
    * function to return name and emails as array list
    */
   function findMail($con)
   {
        $data = null;
        $query = "SELECT username, uid from tbl_user";
        $stmt=$con->prepare($query);
        if($stmt->execute())
        {      
                $data = [];
                $stmt->bind_result($name, $email);
                while ($stmt->fetch())
                {
                        $email = htmlspecialchars($email);
                        $name = htmlspecialchars($name);
                        $data[] = array('name' => $name, 'email' => $email);
                }
        }
        return $data;
    }

    try
    {
        $con = new mysqli($host,$user,$password,$database);
        if($con->connect_error)
        {
                throw new Exception("Goof Up");
        }      
        mysqli_set_charset($con, "utf8");

        $result['data'] = findMail($con);
    }
    catch(Exception $e){
        $result['error'] = true;
    }

    echo json_encode($result);
    exit;
}
?>
<!DOCTYPE>
<head>
<title>TEST 1</title>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    <script type="text/javascript">

        $(function(){
                var retryCounter = 0;
                var repeatInterval = 3000;
                var repeatCall = function(){
                        if(retryCounter >= 3) {
                                console.log('max retries reached');
                                return;
                        }
                        console.log('Calling...');

                        $.ajax({
                                url: "test.php?ajax=1",
                                dataType: "json"
                        })
                        .done(function( result, textStatus, xhr ) {
                            // data = the json encoded result from errScript.php
                                console.log("received data from errScript.php");

                                if(!result) {
                                        console.log('STOPPED due to invalid/empty data');
                                        return;
                                }

                                // on error, retry and increase counter
                                if(result.error)
                                {
                                        setTimeout(repeatCall, repeatInterval);
                                        retryCounter++;
                                        return;
                                }

                                $.each(result.data, function(k, v){
                                        document.write(v.name + " --- " + v.email + "<br />");
                                });
                   }).fail(function(xhr, textStatus, err) { console.log('error'); });
                };

                setTimeout(function() { repeatCall(); }, repeatInterval);      
        });

   </script>

</head>
<body>
        <h1> TEST 1 </h1>
</body>  
</html>

【讨论】:

  • 嗨!从我收集的内容来看,您所做的更改根本不使用 try catch 块来捕获异常。是这样吗 ?我也很少使用 Ajax,所以我发现尝试这个有点困难。但我认为我需要从我的 findMail 函数中完全删除 try catch 块。我正在尝试进行更改以尝试此操作。谢谢
  • 你好,Ole K!所以我试着用你的建议做点什么。我创建了一个不起作用的文件,但我无法在此处发布它,因为它说它对 cme​​ts 来说太长了。请有人指导我如何在这里发布我的代码。谢谢。
  • @Ajoo 我已将示例更新为将两者都放在一个文件中-但我不建议这样做-优秀的(PHP)程序员总是将“图形”部分与代码部分分开。提示:搜索 Smarty 模板引擎
  • 我知道根据规则这里不考虑它,虽然我向管理员道歉,但我不得不说谢谢你的帮助!!
【解决方案2】:

在一定条件下使用ob_start和ob_flush一定是和浏览器渲染有关。

我注意到当我将 php header("Content-Encoding: none") 设置为禁用 gzip 压缩时:

更新 - 添加示例

<?php 
header("Content-Encoding: none"); 

ob_end_clean();
ob_start(); 

for($i=0;$i<5;$i++) 
{ 
    echo 'No. '.$i."<br>";
    ob_flush();
    flush();
    sleep(2);
}
?>

它正确冲洗。查看以下链接的更多详细信息

PHP Streaming/Output Buffering no longer working

For php flush - how to disable gzip for specific file?

【讨论】:

  • 嗨,我已经在我创建的各种 sn-ps 中浏览并尝试了这些选项,但没有成功。由于某种未知原因,睡眠功能将回声置于延迟的最后。输出在接近尾声时同时发生。这是一个小sn-p,如果有人可以找到如何使其按预期工作,那么这将得到解决&lt;?php header("Content-Encoding: none"); ob_start(); for($i=0;$i&lt;10;$i++) { echo 'No. '.$i."&lt;br&gt;"; ob_flush(); flush(); sleep(2); } ?&gt;
  • @Ajoo 尝试添加ob_end_clean();,如更新后的答案所示
  • @Ole K——哇!工作很棒!最后 sleep & echo 是朋友。我也对您通过 JQuery 和 Ajax 进行的原始修改非常感兴趣。 (我相信使用睡眠不是一个好主意。)。请查看此块上方的最后一条评论,我在其中发布了指向我创建的文件的链接,以尽我所能实现该文件的 Jquery 和 Ajax 版本。请找出错误所在。 :-)
猜你喜欢
  • 2012-03-20
  • 2011-07-15
  • 1970-01-01
  • 2013-07-13
  • 1970-01-01
  • 2013-10-11
  • 1970-01-01
  • 2014-04-02
  • 2014-06-17
相关资源
最近更新 更多