检查随机字符串不在数据库中

时间:2015-04-17 13:19:15

标签: php

我有以下似乎永远运行的功能。它创建一个随机字符串,然后检查它是否在数据库中。如果它是它应该一次又一次地运行,直到它有一个是新的。然后它应该将值返回给我

  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;
        }

3 个答案:

答案 0 :(得分:2)

  1. 您的具体问题是您的支票是倒退的。您正在循环直到找到重复内容,这可能需要相当长的时间或永远。
  2. 即使您修复了它,这也是一个糟糕的算法。生成新的唯一代码需要花费更长的时间,数据库中的代码越多,因为重复的可能性会增加。特别是如果你的代码只有6个字符,复制的机会就会增加很多。
  3. 请注意,您也很容易使用race conditions代码(从这个角度考虑)。

    有两种方法可以生成唯一ID:

    1. 使用递增计数器,这意味着您正在使用中央生成器来跟踪现有ID
    2. 使用分散的方法,你跟踪你的id,但是你使用的算法足够随机并且有足够大的空间,碰撞不太可能是在实践中无关紧要
    3. 你结合了两个世界中最糟糕的东西:你正在使用一个中央系统来跟踪你的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

答案 1 :(得分:0)

while (true)是一件危险的事情。正如您所指出的,它默认为一次又一次地运行创建infinite loop

使用auto-incremented value(链接假定为MySQL)或使用PHP生成唯一ID(例如uniqid()),你会更好。

您可以通过为常用单词添加前缀或后缀,例如促销,填充或散列它们来创建标准长度,从而进一步扩展这些值。

答案 2 :(得分:-2)

假设您只是想生成一个未记录在数据库中并考虑到上下文的promocode,我建议您稍微改变一下态度:

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。这将大大缩短查询时间。