5

嗨,我需要生成 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 下的 PHP 5)吗?

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

感谢您的输入。

4

10 回答 10

8

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

另外,为什么你不能只做连续的帐号,每次都增加一个?使用这种方法,您只需要读取数据库中当前的最大 id 并增加它。

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

您真的应该考虑其他一些方法:
我强烈建议您每次创建客户时都增加客户编号。事实上,如果你正确地设置了你的数据库(在 id 列上自动增加),你甚至不必设置 id。每当您插入新客户时,都会为您设置 ID。

于 2008-09-19T01:00:50.350 回答
3

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

. 图形用户界面

如果尽可能少地需要一个真正唯一的 id,请考虑使用 GUID,如果不能在代码中创建一个,您的数据库很可能能够在插入时为您分配。尽管它不是非常用户友好,但它保证是唯一的。但是,结合数据库在插入时生成的顺序 AccountRecordId,您将拥有可靠的组合

. 复合键:随机+顺序

解决所有需求的一种方法,虽然表面上感觉有点笨拙,但是从 5 位(或更多)的顺序 db 密钥创建一个复合帐号,然后再创建一个 5 位随机数。如果随机数重复,则无关紧要,因为顺序 ID 将保证整个帐号的唯一性

于 2008-09-19T01:48:39.300 回答
2

这里不需要使用递归调用。在针对不存在作为条件的功能测试中运行一个简单的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

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

于 2008-09-19T01:03:30.030 回答
1

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

我知道这在巨大的数字范围内似乎不太可能,但可能会出现问题,只会让你回到上一个电话,这将再次称自己为恶心。

于 2008-09-19T01:03:00.720 回答
1

按顺序生成帐号存在安全风险 - 您应该找到其他算法来执行此操作。

于 2008-09-19T01:20:41.253 回答
1

或者,您可以维护一个单独的表,其中包含一个生成的、已知是唯一的帐号的缓冲区。这个表应该有一个自动递增的整数 id。当您想要一个帐号时,只需拉出缓冲区中索引最低的记录并将其从该表中删除。有一些定期运行的进程来补充缓冲区并确保它有容量>>正常使用。优点是最终用户创建帐号所花费的时间基本上是恒定的。

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

于 2008-09-19T01:27:53.233 回答
0

您不需要在这里使用递归。一个简单的循环将同样快并且消耗更少的堆栈空间。

于 2008-09-19T01:02:02.937 回答
0

你可以把它放在一个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
于 2008-09-19T01:02:14.887 回答
0

为什么不:

lock_db
do
    account_num <= generate number
while account_num in db

put row with account_num in db

unlock_db
于 2008-09-19T01:04:08.720 回答
0

为什么不让数据库处理这个?在 SQL Server 中,您可以只拥有一个从 100000000 开始的标识列。或者您可以在您拥有的任何数据库中使用 sql。只需获取最大 id 加 1。

于 2008-09-19T01:05:35.470 回答