【问题标题】:How to make a parallel database change sequential?如何使并行数据库更改顺序?
【发布时间】:2017-11-22 16:52:06
【问题描述】:

我正在使用 WebAPI 和 Entity Framework 6 开发一个项目。

有一个控制器带有一个方法,可以将一个新的实体任务添加到数据库中。在添加任务之前为它计算了一个唯一的名称。部分名称基于数据库中已保存的任务。如果你发出两个并行请求,你可以生成相同的名字,这个问题是通过锁来解决的。

如果两个 WebAPI 服务器正在运行并连接到同一个数据库,我如何防止生成相同的名称?

是否可以在数据库级别添加将Task添加到顺序队列的算法?

简化代码:

    [HttpPost]
    [Route("add")]
    public IHttpActionResult AddTask()
    {
        using (var db = CreateDbContext())
        {
            Task task = new Task();

            lock (lockAdd)
            {
                DateTime dateTime = DateTime.UtcNow;

                string preName = dateTime.ToString("yyMMdd-HHmm-");

                var query = db.Tasks.Where(t => t.Name.StartsWith(preName)).Select(t => t.Name);

                List<string> tasksNames = query.ToList();

                task.Name = preName + (tasksNames.Count + 1).ToString("D4");

                db.Tasks.Add(task);
                db.SaveChanges();
            }

            return Ok();
        }
    }

Сolumn "Name" 不能是唯一的。 任务从未删除。 对于每个新日期(新分钟),计数器必须从 1 开始。

【问题讨论】:

  • 最简单的方法可能是将逻辑添加到数据库中并从那里返回值(可能是插入触发器)。这样,它将始终得到妥善处理。否则,无论如何您都必须拥有一个唯一索引并在插入相同名称时处理异常。

标签: c# postgresql asp.net-web-api entity-framework-6


【解决方案1】:

您应该使用 SEQUENCE 在数据库端生成数据。 Docs here。在这种情况下,数据库保证唯一性。 或使用 Guid (UUID) - 它提供唯一键。 Docs here 在这种情况下,通过 UUID 的想法保证唯一性

【讨论】:

  • 对于每个新日期(新分钟),计数器必须从 1 开始
【解决方案2】:

除了上面的答案,还可以用C#生成Guid: https://msdn.microsoft.com/en-us/library/system.guid.newguid%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

唯一性得到保证,因为 GUID 包含服务器时间和服务器的 MAC 地址。还有一些长度较短的解决方案,例如像 Snowflake 这样的 64 位 UUID 生成器。有关 C# 端口示例,请参阅: https://github.com/mschuler/UniqueIdGeneratorhttps://github.com/ccollie/snowflake-net/blob/master/Snowflake/IdWorker.cs

(注意:如果您使用单例 Snowflake 生成器,则只需要锁定 ID 生成器,因为唯一性由在同一毫秒内的增量计数器保证,最多 2^12 个 ID/毫秒/服务器。第二个source 已经为此提供了一个锁)。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2012-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-21
  • 1970-01-01
  • 2017-08-04
相关资源
最近更新 更多