【问题标题】:PHP Try and Catch for SQL Insert用于 SQL 插入的 PHP Try and Catch
【发布时间】:2010-12-27 11:29:50
【问题描述】:

我的网站上有一个页面(高流量),在每次页面加载时都会插入。

如果系统无法插入 MySQL,我很好奇(捕获错误)并继续的最快和最安全的方法。我应该使用 try/catch 还是 die 或其他东西。我想确保插入发生,但如果由于某种原因它不能,我希望页面继续加载。

...
$db = mysql_select_db('mobile', $conn);
mysql_query("INSERT INTO redirects SET ua_string = '$ua_string'") or die('Error #10');
mysql_close($conn);
...

【问题讨论】:

  • 关于“或死”的使用:phpfreaks.com/blog/or-die-must-die
  • 至于异常与检查返回值,这取决于有多少点可能会产生错误。有了一两点,我会进行错误检查,因为在这种情况下它的性能更高并且可读性更高。一旦你在一个代码块中进行了三个或更多的错误检查,异常就会变得更具可读性。这一切都是为了降低圈复杂度。请注意,这涵盖了您处理错误的要点;如果你谈论的是信号错误,你会得到不同的指导。

标签: php mysql performance error-handling


【解决方案1】:
$new_user = new User($user);
$mapper = $this->spot->mapper("App\User");

try{
    $id = $mapper->save($new_user);     
}catch(Exception $exception){

    $data["error"] = true;
    $data["message"] = "Error while insertion. Erron in the query";
    $data["data"] = $exception->getMessage();

    return $response->withStatus(409)
    ->withHeader("Content-Type", "application/json")
    ->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));        
}

如果发生错误,你会得到这样的->

{
    "error": true,
    "message": "Error while insertion. Erron in the query",
    "data": "An exception occurred while executing 'INSERT INTO \"user\" (...) VALUES (...)' with params [...]:\n\nSQLSTATE[22P02]: Invalid text representation: 7 ERROR:  invalid input syntax for integer: \"default\"" }

状态码:409。

【讨论】:

  • 错误拼写错误。 “查询错误”
【解决方案2】:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

我不确定是否有 mysql 版本,但添加这行代码允许抛出 mysqli_sql_exception。
我知道,经过了很长时间,问题已经被检查回答,但我得到了不同的答案,它可能会有所帮助。

【讨论】:

  • 是的,您可能有不同的答案。请在答案中添加更多详细信息,例如在哪里添加代码行和详细解释代码的链接?
  • 只要在 php 文件中使用它就可以捕获 mysqli_sql_exceptionS。
  • 因为 mysql 已在 PHP 7.0 中删除,所以应该/需要使用 mysqli 的东西。另请参阅此处的答案以及更多解释:stackoverflow.com/questions/14578243/…
【解决方案3】:
    $sql = "INSERT INTO   customer(FIELDS)VALUES(VALUES)";
    mysql_query($sql);
    if (mysql_errno())
    {
            echo "<script>alert('License already registered');location.replace('customerform.html');</script>";
    }   

【讨论】:

    【解决方案4】:

    您可以自行实现在 mysql 查询失败时抛出异常。您需要为 mysql_query 函数编写一个包装器,例如:

    // user defined. corresponding MySQL errno for duplicate key entry
    const MYSQL_DUPLICATE_KEY_ENTRY = 1022;
    
    // user defined MySQL exceptions
    class MySQLException extends Exception {}
    class MySQLDuplicateKeyException extends MySQLException {}
    
    function my_mysql_query($query, $conn=false) {
        $res = mysql_query($query, $conn);
        if (!$res) {
            $errno = mysql_errno($conn);
            $error = mysql_error($conn);
            switch ($errno) {
            case MYSQL_DUPLICATE_KEY_ENTRY:
                throw new MySQLDuplicateKeyException($error, $errno);
                break;
            default:
                throw MySQLException($error, $errno);
                break;
            }
        }
        // ...
        // doing something
        // ...
        if ($something_is_wrong) {
            throw new Exception("Logic exception while performing query result processing");
        }
    
    }
    
    try {
        mysql_query("INSERT INTO redirects SET ua_string = '$ua_string'")
    }
    catch (MySQLDuplicateKeyException $e) {
        // duplicate entry exception
        $e->getMessage();
    }
    catch (MySQLException $e) {
        // other mysql exception (not duplicate key entry)
        $e->getMessage();
    }
    catch (Exception $e) {
        // not a MySQL exception
        $e->getMessage();
    }
    

    【讨论】:

    • @Anonymous,这里有一个稍微不同的方法——你只是抛出一个通用的异常,你不知道抛出了哪种异常。当然,您可以将errno 传递为$codeException 的第二个参数)并在catch 块中检查它,但这并不全面。这就是为什么我写了这个答案,尽管这个问题已经有 2 个答案,利用包装器为 mysql_query throwing expcetion。所以,是的,它是相似的,但在概念上并不完全相同。
    • 我明白,你的理解错误的类型,而我的只是为了易于使用。 :)
    • easy of use 是如此依赖于人的术语。我宁愿使用我的代码(实际上我有自己的ORM,但也有自己的例外),尤其是在大型项目中,因为它是ease of use。由于ease of use,John Doe 可以采用您的解决方案。我们都可以选择最适合我们需求的解决方案,对吧?
    【解决方案5】:

    详细说明yasaluyari 的回答我会坚持这样的:

    我们可以修改我们的mysql_query如下:

    function mysql_catchquery($query,$emsg='Error submitting the query'){
        if ($result=mysql_query($query)) return $result;
        else throw new Exception($emsg);
    }
    

    现在我们可以像这样简单地使用它,一些很好的例子:

    try {
        mysql_catchquery('CREATE TEMPORARY TABLE a (ID int(6))');
        mysql_catchquery('insert into a values(666),(418),(93)');
        mysql_catchquery('insert into b(ID, name) select a.ID, c.name from a join c on a.ID=c.ID');
        $result=mysql_catchquery('select * from d where ID=7777777');
        while ($tmp=mysql_fetch_assoc($result)) { ... }
    } catch (Exception $e) {
        echo $e->getMessage();
    }
    

    注意它有多美。每当任何 qq 失败时,我们都会遇到错误。您还可以注意到,我们现在不需要将写入查询的状态存储到$result 变量中进行验证,因为我们的函数现在自己处理它。和它处理选择的方式一样,它只是将结果分配给一个变量,就像普通函数一样,但在自身内部处理错误。

    另外请注意,我们不需要显示实际错误,因为它们具有巨大的安全风险,尤其是对于这个过时的扩展程序。这就是为什么我们的默认设置在大多数情况下都很好。然而,如果我们确实想通知用户某些特定的查询错误,我们总是可以传递第二个参数来显示我们的自定义错误消息。

    【讨论】:

      【解决方案6】:

      检查documentation 表明它在错误时返回false。所以使用返回状态而不是or die()。如果失败,它将返回 false,您可以记录(或任何您想做的事情)然后继续。

      $rv = mysql_query("INSERT INTO redirects SET ua_string = '$ua_string'");
      if ( $rv === false ){
           //handle the error here
      }
      //page continues loading
      

      【讨论】:

      • 我不认为mysql_query会抛出异常。
      • 确实,mysql_querymysqli_query 都不会抛出异常。 PDOStatement::execute 会,但前提是您在调用 PDOStatement::execute 之前先调用 PDO::setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)
      【解决方案7】:

      这可以解决问题,

      function createLog($data){ 
          $file = "Your path/incompletejobs.txt";
          $fh = fopen($file, 'a') or die("can't open file");
          fwrite($fh,$data);
          fclose($fh);
      }
      $qry="INSERT INTO redirects SET ua_string = '$ua_string'"   
      $result=mysql_query($qry);
      if(!$result){
          createLog(mysql_error());
      }
      

      【讨论】:

      • 我原则上不是[或死]的粉丝。
      【解决方案8】:

      如果你想记录错误等,你应该使用 try/catch,如果你不这样做;只需将@放在mysql_query之前

      编辑: 你可以像这样使用try catch;这样您就可以记录错误并让页面继续加载

      function throw_ex($er){  
        throw new Exception($er);  
      }  
      try {  
      mysql_connect(localhost,'user','pass'); 
      mysql_select_db('test'); 
      $q = mysql_query('select * from asdasda') or throw_ex(mysql_error());  
      }  
      catch(exception $e) {
        echo "ex: ".$e; 
      }
      

      【讨论】:

      • mysql 函数没有抛出任何异常。
      • 很好的例子,这似乎是最合适的方法,我也会坚持下去。优势是显而易见的——你会意识到你必须在一个块中执行 5 个查询,如果其中任何一个因异常而失败,你就会滚蛋。不过我会详细说明一下。
      • 好例子和好方法,我的案例的结果:例如:异常 'Exception' 带有消息 'Duplicate entry '4' for key 'PRIMARY'' in 。谢谢
      【解决方案9】:

      使用上一篇文章中描述的任何方法以某种方式捕获 mysql 错误。
      最常见的是:

      $res = mysql_query('bla');
      if ($res===false) {
        //error
        die();
      }
      //normal page
      

      这也可以:

      function error() {
        //error
        die()
      }
      $res = mysql_query('bla') or error();
      //normal page
      

      try { ... } catch {Exception $e) { .... } 不起作用!

      注意:与您的问题没有直接关系,但我认为如果您向用户展示一些有用的东西会更好。我永远不会重新访问只显示空白屏幕或任何神秘错误消息的网站。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-29
        • 2016-02-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多