【问题标题】:Not generating random unique Id in a multithreaded environment for a SQL column having Bigint as datatype不在多线程环境中为具有 Bigint 作为数据类型的 SQL 列生成随机唯一 ID
【发布时间】:2021-10-13 08:57:37
【问题描述】:

我有一个数据类型为Bigint 的 SQL 列,因此当我在多线程环境中使用 C# Random 类生成唯一编号时,我看到有重复值而不是唯一值,我只能看到系统 GUID是生成唯一 ID 的唯一选项,请您帮我解决这个问题。

private Object thisLock = new Object();  
public Random a = new Random(DateTime.Now.Ticks.GetHashCode());
private void NewNumber()
{
  lock (thisLock)  
  {  
    MyNumber = a.Next(0, 10);
  }
}

【问题讨论】:

  • 为什么要使用当前 Tick 计数的 哈希码 作为随机种子?
  • @gunr2171 我尝试了很多东西,但没有任何效果。
  • @Mysterious288 你用的是什么数据库? MS SQL、PostgreSQL、MySQL?
  • 随机不生成唯一数字。首选incrementalsGUIDs
  • 请不要使用new Random(DateTime.Now.Ticks.GetHashCode()) - 它比new Random() 更糟糕。

标签: c# multithreading


【解决方案1】:

Random 类生成随机值,而不是唯一值。在您的示例代码中,唯一整数的最大数量为 10(从 0 到 9)。因此,如果您至少调用此方法 11 次,则可以保证有一个或多个重复。

对于数据库,您应该使用标识列。

【讨论】:

    【解决方案2】:

    您的代码应该正常运行而没有错误,而我没有发现错误。重复的数字可能是因为它们的范围很小。

    您可以使用以下类来生成范围之间的随机数。每次从所需范围返回一个数字。

    class UniqueRandom 
    {
      private readonly List<int> _currentList;
      private readonly Random _random = new Random();
    
      public UniqueRandom(IEnumerable<int> seed) 
      {
        _currentList = new List<int>(seed);
      }
    
      public int Next()
      {
        if (_currentList.Count == 0) 
        {
          throw new ApplicationException("No more numbers");
        }
    
        int i = _random.Next(_currentList.Count);
        int result = _currentList[i];
        _currentList.RemoveAt(i);
        return result;
      }
    }
    

    UniqueRandom类创建实例并在NewNumber()方法中调用Next()方法

    UniqueRandom u = new UniqueRandom(Enumerable.Range(0, 10));
    private Object thisLock = new Object();  
    public Random a = new Random(DateTime.Now.Ticks.GetHashCode());
    private void NewNumber()
    {
      lock (thisLock)  
      {  
        MyNumber = u.Next();
      }
    }
    

    【讨论】:

      【解决方案3】:

      SQL Server Bigint 类型等效于 C# Int64 (long) 类型。要在 C# 中生成随机的 long 值,请查看 this 问题。为确保随机数也是唯一的,请在相关数据表列中添加unique constraint。如果数据库中已经存在随机值,catch 约束违反异常,并使用新的随机值重试。

      关于如何在多线程环境中正确使用Random类,看看这个问题:Is C# Random Number Generator thread safe?

      【讨论】:

      • 虽然没关系,但在客户端生成一个随机数,尝试通过 dbms,捕获约束异常并重试是相当无效的。如果我真的需要服务器端的随机 bigint,我会编写一个存储过程来实现这一点,而无需在服务器和客户端之间进行往返。我仍在等待答案,这里使用的是什么 DBMS,以及是否真的需要随机数。
      • @Steeeve 在临时数据库中插入重复的Bigint 值的概率是如此之小,假设随机值生成正确,那么在获得约束违反异常后重试INSERT应该是相当罕见的情况。我不会太担心性能影响。
      • ACK :) 我仍然会在存储过程中实现它。
      • @Steeeve 我正在使用 SQL Server,但我无法存储 proc,因为我正在使用 fluentd 工具从源获取日志并将其推送到数据库。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-22
      • 1970-01-01
      • 2015-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多