使用随机类 C# 生成 BIGINT 密钥



我的SQLDB中有一个主键作为BIGINT(64位(现在,由于 C# 没有直接生成 64 位密钥的机制,我使用以下代码来生成密钥。我的问题是我在键列中看到随机但聚集的值。

tl.ID = (this.r.Next() << 32) | this.r.Next();

其中 tl.ID 是 LINQ to SQL 类,并且是 LONG。this.r 是随机的实例

Random r = new Random((int)DateTime.Now.Ticks);

在数据库中看到的一些值:

MAX:2147483647
Top few values:
2147478265
2147478479
2147478526
2147479034
2147479663
2147480695
2147480783
2147480887
2147480984
2147481817
2147482099
2147482607
2147483321
2147483391
2147483558
2147483644
2147483647

首先,主键应该是唯一的。

将标识列添加到您的数据库/自动增量,您会没事的。

如果需要,添加

具有自动增量的新身份列,删除旧身份列,将新身份重命名为旧名称,您将没事

您必须在

移位之前将数字转换为很久,否则这只会移出有效位。

tl.ID = ((long)this.r.Next() << 32) | this.r.Next();

请记住,正如评论中提到的问题所指出的那样,此方法并不完美,因为Random.Next()只返回正值,因此您实际上只能获得 62 个随机位。

正如 AlexDev 所提到的,问题出在第一种情况下,在将其移动 32 位之前,它应该转换为 long。

问题 1:使用随机数生成主键可能是一个坏主意,因为最终你最终会遇到冲突,所以使用你拥有的代码,你会遇到问题,除非你在使用它之前检查每个生成的键都是唯一的。如果您确实需要随机数作为键,请使用下面的解决方案。

问题2:随机类方法 Next 生成一个 int,在您的例子中为 32 位,这将环绕,您将只有预期范围的一半。另一个问题是标准随机类不是一个好的随机生成器。

问题3:使用由 Random 生成的两个 Int32 并将一个(移入长(并附加另一个不是生成 64 位随机数的最佳方法,您的双倍机会会增加(这是一个超出本次讨论范围的加密主题,所以我将把它留在那个:)(

解决方案:要真正生成随机 Int64,您可以使用 Random 甚至更好的 RandomNumberGenerator 为您的 64 位数字填充一个 8 字节的数组,并将该数组转换为长 (Int64(,例如:

using System.Security.Cryptography;
var rng = RandomNumberGenerator.Create();
//bytes to hold number
var bytes = new byte[8];
//randomize
rng.GetNonZeroBytes(bytes);
//Convert
long random = BitConverter.ToInt64(bytes, 0);

这将生成一个真正的 64 位随机数,RandomNumberGenerator 是比 Random 类更好的随机生成器(更难预测(。

最新更新