我试图运行以下代码来显示"不一致";当数据库并行更新时(使用多个线程),但是当我运行这段代码时,表中的值始终是一致性,即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
。