2014-09-05 111 views
2

我不確定這是PHP中的錯誤,MySQL還是我很愚蠢,但很偶然(並且非常罕見),我們將其稱爲mysqli::query,並且不會獲得FALSEmysqli_result對象。mysqli ::查詢不返回FALSE或mysqli_result - PHP的錯誤?

我們正在運行:

  • PHP 5.5.9-1ubuntu4.3
  • 的MySQL版本15.1 DISTRIB 38年5月5日,MariaDB的,使用readline的5.1 Debian的Linux-GNU(x86_64的)(使用Galera)

查詢運行是SHOW STATUS LIKE "Questions"

根據the manualSHOW查詢我們應該時刻找回要麼FALSEmysqli_result對象,但我們沒有得到任何。這行代碼每天運行超過10萬次,每週大約失敗一次。

下面是從我們的數據庫封裝代碼片段(該功能只會被用於讀查詢):

public function read($query, $cache = 0) { 
    $total_time_start = microtime(1); 

    $deadlock_retries_done = 0; 
    $deadlock_retries_max = 10; 
    $other_error_retries_done = 0; 
    $other_error_retries_max = 10; 

    $return = array(); // Keeps IDEs happy! 

    while (true) { 
     $start = microtime(1); 
     $return = array(); 
     $q = $this->connection->query($query, MYSQLI_STORE_RESULT); 
     $this->debug_last_query = $query; 

     // Was there an error? 
     if ($q === false) { 
      $error = $this->connection->error; 
      switch ($error) { 
       case 'Deadlock found when trying to get lock; try restarting transaction': 
       case 'Lock wait timeout exceeded; try restarting transaction': 
        $deadlock_retries_done++; 
        if ($deadlock_retries_done == $deadlock_retries_max) { 
         throw new SQLException($error . '. Re-tried with deadlock ' . $deadlock_retries_done . ' times. Query: ' . $query); 
        } else { 
         continue; // Try again 
        } 
        break; 

       case 'WSREP has not yet prepared node for application use': 
        $other_error_retries_done++; 
        if ($other_error_retries_done == $other_error_retries_max) { 
         throw new SQLException($error . '. Re-tried with error ' . $other_error_retries_done . ' times. Query: ' . $query); 
        } else { 
         if ($this->in_transaction) { 
          throw new SQLException($error . '. Re-tried with error ' . $other_error_retries_done . ' times. Cannot reconnect as in transaction. Query: ' . $query); 
         } else { 
          $this->close_and_establish_new_database_connection(); 
          continue; // Try again 
         } 
        } 
        break; 

       default: 
        throw new SQLException($error . '. Query: ' . $query); 
        break; 
      } 
     } 

     // Check we have got a result 
     if (!$q instanceof mysqli_result) { 
      throw new SQLException('Seemed to have a result but it is not a mysqli_result object. Query: ' . $query); 
     } 

     // All worked ok, deal with the result 
     while (($row = $q->fetch_assoc())) { 
      $return[] = $row; 
     } 
     $end = microtime(1); 

     $this->debugData($start, $end, $query, 'DB', '', $total_time_start, $cache); 

     $this->last_affected_rows = $q->num_rows; 
     $q->free_result(); 
     break; 
    } 

    return $return; 
} 

顯然它調用未包含在片段的一些功能,但你應該明白。

引發的異常是:

SQLException: Seemed to have a result but it is not a mysqli_result object. Query: SHOW STATUS LIKE "Questions" 

我會加入到我們的異常信息的東西輸出什麼$q實際上是等待它再次發生。

有沒有其他人每個人都經歷過這樣的事情,你有什麼建議嗎?我非常感謝你的幫助。由於


編輯:

我們只是有它發生在一個非常簡單的SELECT cols FROM table WHERE key = x LIMIT 1;類型的查詢(未顯示出於安全原因,真正的查詢,但它是關於你可以有最簡單的查詢) 。這發生在我額外的日誌記錄已經生效之前。當我有希望獲得更多細節時,我會再次更新。

+0

''我們沒有得到'',所以只需顯示'var_dump($ q)'得到了什麼。 – xdazz 2014-09-05 09:43:09

+0

@xdazz是的,我已經添加了一些額外的日誌記錄,下次發生時,我會發布更多的實際返回的細節。 – 2014-09-05 10:03:41

回答

1

在你的代碼,如果$qfalse,它仍然會進入的,如果條件:

if (!$q instanceof mysqli_result) { 

也許你需要else if代替。

+0

不,它不會。如果'$ q === false',那麼它會碰到上面的部分,並且或者拋出一個更早的異常或'continue;'到另一個循環迭代中。 – 2014-09-05 10:02:21

+0

我的歉意,你說得對,'$ q'可能是假的。我期待switch中的'continue;'被'switch'忽略並繼續'while'循環。實際上'繼續;'在開關中與'break;'http:// stackoverflow相同。com/a/12349889/1178671,以便解釋它。 'continue'應該是'continue 2;'。再次抱歉我上面的不正確評論。 – 2014-09-05 14:49:11