2015-04-17 79 views
0

我有以下函數似乎永遠運行。它創建一個隨機字符串,然後檢查它是否在數據庫中。如果是的話,它應該一次又一次運行,直到它有一個新的。它應該然後返回給我的價值檢查隨機字符串不在數據庫中

public function checkPromo(){ 
      $continue = true; 
      while ($continue){ 
       $promo = $this->getRandString(6); 

         $query = sprintf("SELECT * FROM table WHERE field=%s", 
         $this->db->cleanCode($promo, "text")); 
         $result = $this->db->query($query); 

         if($this->db->num_rows($result) >= 1){ 
          $continue = false; 
         } 
      } 
      return $promo; 
     } 

回答

-2

假設你只是想生成沒有記錄在數據庫中的促銷碼,並考慮到環境中,我勸你改變態度一點點:

public function generatePromo(){ 
$promo = $this->getRandString(6); 

$query = sprintf("SELECT * FROM table WHERE field=%s", $this->db->cleanCode($promo, "text")); 
$result = $this->db->query($query); 

if($this->db->num_rows($result) > 0){ # in case a record with this "text" already exists, run this method again 
    $this->generatePromo(); 
} else { 
    return $this->promo = $promo; # otherwise return the value/store it in the object 
}} 

如果你希望你的表包含只有唯一的價值,那麼我建議你讓它UNIQUE。這將顯着減少查詢時間。

+1

這段代碼很容易出現競爭狀況,甚至可能導致堆棧溢出。它還包含一個bug,它不會從遞歸調用中返回任何東西。 – deceze

+1

添加一條評論以使其更清晰:此代碼採用與問題中相同的不可取的方法。如果沒有找到合適的隨機字符串,它也會使它變成遞歸函數而變得更糟,易受堆棧溢出的影響。隨着更多的隨機字符串被添加,代碼仍然會呈指數級慢。 – Grampa

0

while (true)是一件危險的事情。如您所述,其默認爲反覆運行創建infinite loop

你會利用auto-incremented value更好的報價(鏈接假定MySQL的),或者用PHP生成一個唯一的ID(如uniqid())。

您可以通過前綴或後綴普通單詞,例如promo或padding或散列它們以創建標準長度來進一步擴展這些值。

+0

請注意,您鏈接的'uniqid'功能對於生成唯一標識非常不利。 – deceze

2
  1. 您的具體問題是您的支票倒退。您正在循環播放,直到您找到重複的內容,這可能需要一段時間或永​​久。
  2. 即使您修復了它,這也是一個糟糕的算法。由於重複數據的機會增加,因此數據庫中的代碼越多,生成新的唯一代碼的時間就會越長。特別是如果你的代碼長度只有6個字符,重複的機會就會增加很多。

請注意,您也傾向於使用代碼race conditions(從這個角度思考)。

有兩種方法來生成唯一ID:

  1. 使用遞增計數器,這意味着你使用的是中央發生器,它保持現有的IDS的軌道
  2. 用分散的方式,你是跟蹤你的ID,但你使用的算法是足夠隨機的,有足夠大的空間,碰撞是如此不太可能,因爲是不相關的實踐

你將兩個世界中最糟糕的結合在一起:你正在使用一箇中央系統來跟蹤你的ID,但是你使用隨機ID來生成它。使用一個或另一個,而不是兩個。

如果您打算使用數據庫,只需使用標準的auto_increment id。如果你想讓它看起來有點隨機,可以用MD5或其他類似的方法來散列它。

或者,簡單地預先生成全部可能的代碼(只有6個字符不是很多),並使用不容易出現競爭條件的方法隨機選擇一個。沿此線的東西:

UPDATE codes 
    SET claimed_user_id = %d 
WHERE claimed_user_id IS NULL 
ORDER BY RAND() 
LIMIT 1 

否則,如果你想分散隨機ID,請使用適當的算法,這是相當多UUID

+0

我會嘗試搶先評論關於MD5的任何評論:這裏幾乎沒有安全問題,因爲這裏沒有什麼可以攻擊的。 MD5對此很好,它的哈希值很短(ish)。 – deceze