为什么用.net并行更新数据库会导致一致的结果



我试图运行以下代码来显示"不一致";当数据库并行更新时(使用多个线程),但是当我运行这段代码时,表中的值始终是一致性,即500。它是如何工作的?

static void Main(string[] args)
for (int i = 0; i < 500; i++) {
Thread t = new Thread(() => Update());
t.Start();
}
await Task.Delay(100000);
}
public static void Update() {
using (var conn = new SqlConnection("mssql-connection-string")) {
conn.Execute("update [table] set counter = counter +1;");
}
}

您拥有的代码不会导致竞争条件,因为您想要UPDATE的行将被锁定,递增,然后锁释放;这意味着任何其他试图同时运行的UPDATE语句都必须"等待";第一个UPDATE完成。

如果你想模拟一个竞争条件,首先将值赋给一个变量;这应该会给你这样的行为:

DECLARE @c int = (SELECT counter FROM dbo.[table]); --I assume table only has 1 row
UPDATE dbo.[table] SET Counter = @c + 1;

这将意味着counter的值将首先分配给变量,这不会锁定读取该行的其他进程。因此,多个并发线程可以同时读取该行,然后将其UPDATE设置为各自的+1值。因此,5个线程可能都将值读取为7,而UPDATE将值读取为7+1(8)。

如果出于某种原因,您确实需要在UPDATE之前将表中的值分配给变量,那么您将希望在查询中使用UPDLOCK提示:

DECLARE @c int = (SELECT counter FROM dbo.[table] WITH (UPDLOCK)); --I assume table only has 1 row
UPDATE dbo.[table] SET Counter = @c + 1;

您可能还需要将事务的隔离级别更改为SERIALIZABLE

最新更新