我正在寻找一种生成唯一订单ID的好方法.你能看到下面代码有什么问题吗?
int customerId = 10000000;
long ticks = DateTime.UtcNow.Ticks;
long orderId = customerId + ticks;
int orderNumber = orderId.GetHashCode();
Run Code Online (Sandbox Code Playgroud)
在创建订单之前,我将检查数据库中的数字是否唯一.
LBu*_*kin 25
如果要将记录存储在数据库中,则应该真正研究可用于生成唯一代理键的功能.在SQLServer中,这将是一个IDENTITY字段,在Oracle中,它将是一个使用SEQUENCE生成新值的字段.
如果有一个令人信服的理由为什么你不能使用你的数据库生成一个唯一的密钥,你应该看一下像Guid - 一个mucher比日期时间操作更高概率生成一个唯一值.Guid可以简单地转换为字符串,因此在这种情况下您的标识符将是一个字符串.
你用哈希做什么并不是一个好主意 - 没有任何关于哈希值得特别注意的东西 - 在很多情况下它们确实会发生碰撞.Guids - 不提供100%保证机器的唯一性,但在一台机器上它们应始终是唯一的.甚至在机器上,他们碰撞的机会极其遥远.此外,使用机器时间作为构建潜在价值的方式受竞争条件的影响(如Eric所述).
Guids是128位值,因此您不能将它们表示为简单int或long.它需要您使用字符串作为您的ID,在您的情况下可能会或可能不会,这取决于其他考虑因素(例如您是否控制数据模型).如果可以使用它们,使用Guid非常简单:
string customerId = Guid.NewGuid().ToString(); // fetch new guid and save as string
string orderNumber = Guid.NewGuid().ToString(); // same story here...
Run Code Online (Sandbox Code Playgroud)
如果您确实必须使用数字标识符,并且您愿意放弃在多个服务器上轻松扩展应用程序,则可以使用自动递增的全局数字来提供唯一键.在应用程序启动时,您必须使用数据库中的下一个可用值(max + 1)为此数字设定种子.然后,您还必须保护此值不受多个线程的并发使用的影响.我会把这个责任包括在一个课程中:
class static UniqueIDGenerator
{
// reads Max+1 from DB on startup
private static long m_NextID = InitializeFromDatabase();
public static long GetNextID() { return Interlocked.Increment( ref m_NextID ); }
}
Run Code Online (Sandbox Code Playgroud)
编辑: 在这个时代,在应用程序层而不是在数据库中生成唯一ID的令人信服的理由非常罕见.您应该真正使用数据库提供的功能.
Eri*_*ert 15
假设您有两个相差100的客户ID,并且它们碰巧订单相隔100个单位.你的独特性就在窗外.
你说你要检查数据库的唯一性; 如果发生碰撞,你不会说你要做什么.你也没有说你将如何处理竞争条件; 假设同时创建了两个冲突订单ID,数据库中也没有.您在两个不同的线程上询问数据库是否该项是唯一的; 它是.然后输入两者,即使检查已完成,也违反了唯一性.
这是获得独特性的一种非常非常糟糕的方式.更好的是将其移动到数据库层.您可以维护一个全局的线程安全的订单计数器,并为每个新订单分配下一个最高订单号.
顺便说一下,多年来我一直在问这个问题的变体作为技术面试问题.我注意到那些试图利用时间作为唯一性来源的人和那些没有被雇用的人之间存在很强的相关性.时间是独特的可怕来源; 很多不同的事情可以同时发生.
更糟糕的是使用随机数.随机数是比时间戳更糟糕的唯一性来源.假设您有一个真正的随机数生成器,可为订单ID生成随机32位整数.在赔率高于五十五美元之前,您需要多少订单才能生成两个具有相同ID的订单?这个答案让很多人感到惊讶:在你有50%的可能性生成两个相同数量的订单之前,它只有大约77,000个(只有9300,直到有1%的机会.)
记住:你所追求的是对独特性的保证.不是一个可能的唯一性,而是一个铁壳保证,一个订单号只指一个订单.如果这就是您所需要的,那么请确保实现它.
| 归档时间: |
|
| 查看次数: |
11389 次 |
| 最近记录: |