【问题标题】:Insert unique sequence number based on another column value根据另一列值插入唯一的序列号
【发布时间】:2016-02-29 08:12:43
【问题描述】:

我有这个 SQL Server 2008 R2 表 (t1):

+----+------+----------+
| id | type | sequence |
+----+------+----------+
| 1  | 'A'  | 1        |
| 2  | 'A'  | 2        |
| 3  | 'A'  | 3        |
| 4  | 'B'  | 1        |
| 5  | 'B'  | 2        |
| 6  | 'C'  | 1        |
+----+------+----------+

例如,要插入必须为 3 的类型“B”的下一个序列,我使用:

void Add(string type)
{
     int i = db.ExecuteScalar("select coalesce(max(sequence) + 1, 1) from t1 where type='" + type + "'"); 
     db.ExecuteNonQuery("insert into t1 (type, sequence) values ('" + type + "', " + i + ")");
}

Add("B");

这很好用,但是如果两个用户同时执行 Add("B") 他们将获得并插入相同的序列

我应该如何防止这种情况发生?

【问题讨论】:

  • 使用存储过程并在同一个事务中执行两个语句。在事务期间,表将被锁定写入和读取。因此,在您完成之前不会运行其他查询。
  • @Helio 谢谢或通过: DbConnection c = db.Open(); DbTransaction t = c.BeginTransaction(); try { /* 选择下一个序列 + 插入到 t1*/ t.Commit(); } 赶上 { t.Rollback(); }
  • @Helio 我应该使用哪个隔离级别:Read CommittedRepeatable Read 还是 Serializable
  • 请参阅"Should questions include “tags” in their titles?",其中的共识是“不,他们不应该”!

标签: c# sql sql-server


【解决方案1】:

您可以添加锁定语句。为了防止死锁,您应该在任务中执行查询。

private static object ExecuteLock = new object();
void Add(string type)
{
    Task.Run(() =>
    {
        lock(ExecuteLock)
        {
            int i = db.ExecuteScalar("select coalesce(max(sequence) + 1, 1) from t1 where type='" + type + "'"); 
            db.ExecuteNonQuery("insert into t1 (type, sequence) values ('" + type + "', " + i + ")");
        }
    });
}

Add("B");

这仅在两个用户使用相同的应用程序和应用程序的相同实例插入唯一序列号时才有效。如果两个用户使用不同的应用程序,则需要在数据库级别解决此问题,如 cmets 中所述

【讨论】:

    猜你喜欢
    • 2012-04-17
    • 2021-03-16
    • 2021-02-28
    • 2023-02-23
    • 2016-01-16
    • 1970-01-01
    • 2015-08-03
    • 2021-11-06
    • 1970-01-01
    相关资源
    最近更新 更多