题
您好,我需要生成 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)?
这是解决这个问题的可接受的方法吗?
感谢您的输入。
解决方案
您意识到这很可能导致堆栈溢出,对吗?随着客户数量的增加,找不到可接受的帐号的可能性也会增加。
另外,为什么不能只使用连续的帐号并每次加一呢?使用这种方法,您只需读取数据库中当前的最大 id 并递增它。
抱歉这么直白,但你的解决方案是解决问题的糟糕方法。它将使用大量内存(因为堆栈可能无限增长),并且会对数据库进行大量昂贵的调用。
你真的应该考虑其他一些方法:
我强烈建议您每次创建客户时只增加客户编号。事实上,如果您正确设置数据库(在 id 列上自动递增),您甚至不必设置 id。每当您插入新客户时,都会为您设置 ID。
其他提示
我真的不认为这可以归结为递归与递归。随着数据集的增长以及随机数生成未正确实现,两者都容易出现问题。我想到了两个想法:
. 。GUID
如果需要一个真正唯一的 ID,并且需要尽可能少的努力,请考虑使用 GUID,您的数据库很可能能够在插入时为您分配,如果不是在代码中创建的话。尽管它不是很用户友好,但它保证是唯一的。但是,与插入时数据库生成的顺序 AccountRecordId 相结合,您将获得可靠的组合
. 。复合键:随机+顺序
解决所有需求的一种方法是从 5 位(或更多)的连续数据库密钥创建一个复合帐号,然后再创建另外 5 位随机数字,尽管表面上感觉有点笨拙。如果随机数重复也没关系,因为顺序 ID 将保证整个帐号的唯一性
这里不需要使用递归调用。在函数中运行一个简单的 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
但是,如果此代码用于玩具以外的任何东西,则随机生成和测试是生成唯一帐号的次优方法。
看起来不错,但我认为你需要某种模具条件,在你放弃之前你会让这个运行多少次?
我知道这在巨大的数字范围内似乎不太可能,但可能会出现问题,让您回到之前的调用,这会再次调用自己,令人作呕。
按顺序生成帐号存在安全风险 - 您应该找到其他算法来完成此操作。
或者,您可以维护一个单独的表,其中包含生成的已知唯一帐号的缓冲区。该表应该有一个自动递增的整数 id。当您需要帐号时,只需提取缓冲区中索引最低的记录并将其从该表中删除即可。有一些定期运行的进程来补充缓冲区并确保其具有容量>>正常使用。优点是最终用户创建帐号所花费的时间基本上是恒定的。
另外,我应该注意到处理开销或递归或迭代的风险,真正的问题是确定性和重复数据库查询的开销。我喜欢 TheZenker 的随机+顺序解决方案。保证生成唯一的 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
为什么不:
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 即可。