生成唯一的帐号-递归调用

时间:2020-03-06 14:24:14  来源:igfitidea点击:

嗨,我需要生成9位数字的唯一帐号。这是我的伪代码:

function generateAccNo()

    generate an account number between 100,000,000 and 999,999,999

    if the account number already exists in the DB 
        call generateAccNo()    /* recursive call */
    else
        return new accout number
    end if

end function

该函数似乎运行良好,但是我对递归调用有点担心。

这会导致任何内存泄漏(Apache 5下的PHP 5)吗?

这是解决这个问题的可接受方法吗?

感谢输入。

解决方案

我们意识到这很可能导致堆栈溢出,对吗?随着客户数量的增加,找不到可接受的帐号的可能性也会增加。

另外,为什么我们不能只做连续的帐号,而每次只增加一个呢?使用这种方法,我们只需要读取数据库中当前的最大id并对其进行递增即可。

抱歉,这么钝,但是解决方案是解决问题的糟糕方法。它会使用大量的内存(因为堆栈可能会无限增长),并且它将对数据库进行大量昂贵的调用。

我们应该真正考虑其他方法:
我强烈建议我们在每次创建客户时仅增加客户编号。实际上,如果我们正确设置了数据库(在id列上具有自动递增的功能),则甚至不必设置id。每当我们插入新客户时,系统都会为我们设置ID。

我们无需在此处使用递归。一个简单的循环将同样快,并且消耗更少的堆栈空间。

我们可以将其放入while循环中:

function generateAccNo()

    while (true) {    

      generate an account number between 100,000,000 and 999,999,999

      if the account number already exists in the DB 
          /* do nothing */
      else
          return new accout number
      end if
    }

end function

看起来不错,但是我认为我们需要某种死亡条件,在放弃之前,我们要让它运行多少次?

我知道在庞大的数字范围内这似乎不太可能,但是可能会出问题,只是使我们退回到上一个呼叫,该呼叫将再次被称为广告博物馆。

此处无需使用递归调用。在功能测试中运行一个简单的while循环,以不存在条件为条件,例如

function generateAccNo()

    generate an account number between 100,000,000 and 999,999,999

    while ( the account number already exists in the DB ) {
         generate new account number;
    }
    return new account number

end function

但是,如果此代码用于玩具以外的其他任何事物,则随机生成和测试是生成唯一帐号的次佳方法。

为什么不:

lock_db
do
    account_num <= generate number
while account_num in db

put row with account_num in db

unlock_db

数据库为什么不处理呢?在SQL Server中,我们可以只具有一个以100000000开始的标识列。或者我们可以在拥有的任何数据库中使用sql。只需获得最大ID加1.

顺序生成帐号是一种安全风险,我们应该找到其他一些算法来实现。

或者,我们可以维护一个单独的表,其中包含一个已生成的缓冲区(称为唯一帐号)。该表应具有一个自动递增的整数ID。当我们需要一个帐号时,只需在缓冲区中检索索引最低的记录并将其从该表中删除即可。有一些定期运行的过程可以补充缓冲区并确保其容量>>正常使用。优点是最终用户花费在创建帐号上的时间量基本上是恒定的。

另外,我应该注意的是处理开销或者递归或者迭代的风险,真正的问题是确定性和重复数据库查询的开销。我喜欢TheZenker的随机+顺序解决方案。保证生成唯一的ID,而不会增加不必要的开销。

我真的不认为这归结于递归与循环,随着数据集的增长以及随机数生成未正确实现,两者都容易出现问题。我想到两个主意:

。图形用户界面

如果需要尽可能少的努力才能获得真正唯一的ID,请考虑使用GUID,如果没有在代码中创建一个ID,则数据库很可能会在插入时为我们分配。尽管不是很友好,但可以保证它是唯一的。但是,与插入时数据库生成的顺序AccountRecordId结合使用时,我们将获得可靠的组合

。复合键:随机+顺序

一种解决所有需求的方法,尽管从表面上看有点麻烦,但它是使用5位数(或者更多)的顺序db密钥创建一个复合帐号,然后再使用5位数的随机性来创建。如果随机数重复,则没关系,因为顺序ID可以保证整个帐号的唯一性