以下是要求:
必须是字母数字组合,8-10个字符长度以便用户易于使用。这些将作为唯一键存储在数据库中。我正在使用Guids作为主键,因此最好提供使用Guid生成这些唯一标识符的选项。
我考虑使用基数转换器将Guid转换为8个字符的唯一字符串。
短小、轻量级算法更受欢迎,因为它会经常被调用。
8 characters - perfectly random - 36^8 = 2,821,109,907,456 combinations
10 characters - perfectly random - 36^10 = 3,656,158,440,062,976 combinations
GUID's - statistically unique* - 2^128 = 340,000,000,000,000,000,000,000,000,000,000,000,000 combinations
* GUID是否100%独特?[stackoverflow]
将GUID转换为字符的问题在于,虽然GUID在统计学上是独特的,但如果取任何子集,则会降低随机性并增加碰撞的几率。您肯定不希望创建非唯一SKU。
解决方案1:
使用与对象和业务规则相关的数据创建SKU。
即,可能有一小组属性使对象唯一(自然键)。将自然键的元素组合、编码和压缩以创建SKU。通常只需要一个日期时间字段(例如CreationDate)和其他几个属性即可实现这一点。您可能会在sku创建中遇到很多问题,但sku对您的用户更加相关。
假设情况如下:
Wholesaler, product name, product version, sku
Amazon, IPod Nano, 2.2, AMIPDNN22
BestBuy, Vaio, 3.2, BEVAIO32
解决方案2:
一种方法是预留一段数字范围,然后按顺序逐个释放它们,永远不会重复使用相同的数字。但是,您仍然可能在该范围内留下空洞。通常情况下,您不需要生成足够的SKU以产生影响,但请确保您的要求允许此操作。
实现方法是在数据库中创建一个名为key
的表格,并具有计数器。该计数器在事务中递增。重要的一点是,软件中的方法不是递增1,而是获取一个块。伪代码如下。
-- what the key table may look like
CREATE TABLE Keys(Name VARCHAR(10) primary key, NextID INT)
INSERT INTO Keys Values('sku',1)
// some elements of the class
public static SkuKeyGenerator
{
private static syncObject = new object();
private static int nextID = 0;
private static int maxID = 0;
private const int amountToReserve = 100;
public static int NextKey()
{
lock( syncObject )
{
if( nextID == maxID )
{
ReserveIds();
}
return nextID++;
}
}
private static void ReserveIds()
{
// pseudocode - in reality I'd do this with a stored procedure inside a transaction,
// We reserve some predefined number of keys from Keys where Name = 'sku'
// need to run the select and update in the same transaction because this isn't the only
// method that can use this table.
using( Transaction trans = new Transaction() ) // pseudocode.
{
int currentTableValue = db.Execute(trans, "SELECT NextID FROM Keys WHERE Name = 'sku'");
int newMaxID = currentTableValue + amountToReserve;
db.Execute(trans, "UPDATE Keys SET NextID = @1 WHERE Name = 'sku'", newMaxID);
trans.Commit();
nextID = currentTableValue;
maxID = newMaxID;
}
}
words = [s.strip().lower() for s in open('/usr/share/dict/canadian-english') if "'" not in s]
mod = len(words)
def main(script, guid):
guid = hash(guid)
print "+".join(words[(guid ** e) % mod] for e in (53, 61, 71))
if __name__ == "__main__":
import sys
main(*sys.argv)
这将产生类似以下的输出:
oranjestad+compressing+wellspring
padlock+discommoded+blazons
pt+olenek+renews