我想在MSSQL中增加一个值(例如,在购买礼品卡后增加用户余额)。单表存储过程死锁
我的存储过程和表的样子:
CREATE TABLE Test_Table ([intCount] [int] NOT NULL)
ALTER PROCEDURE Test_Proc AS
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
UPDATE Test_Table
SET intCount = intCount + 1
COMMIT TRAN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
RETURN(0)
END
我只有在表中的一行简单,我只是增加所有行。
我在C#中产生10个线程,并在每个线程中调用存储过程10次。然而,我在大多数线程中遇到了死锁。我的代码调用此存储过程是这样的:
for (int thread = 0; thread < threads; thread++)
{
new Thread(() =>
{
try
{
for (int ix = 0; ix < count; ix++)
{
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand cmd = new SqlCommand("Test_Proc", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
}
}
}
catch (Exception e)
{
errors++;
}
}).Start();
}
我(UPDLOCK,HOLDLOCK)尝试,但似乎并没有减少死锁的频率。
有无论如何我可以改变存储过程来防止这些死锁?我真的在寻找一个SQL答案,而不是只用C#序列化所有的存储过程调用。
(这与Deadlock with single stored procedure and multiple threads类似,但该问题明确要求如何死锁,而我只是想避免死锁)。
编辑:我修改了存储过程的内容在事务中的代码,但它仍然是死锁。
编辑:错误消息看起来像Transaction (Process ID 124) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
。
编辑:我更新了存储过程的每个反馈,但它仍然死锁。
编辑:它看起来像解释是在:https://stackoverflow.com/a/36831413/1117119。 SERIALIZABLE获取共享锁,然后在写入时将其转换为排它锁。这会导致死锁。
此外,它似乎会发生任何进一步的死锁,因为我只是有太多的线程:SQL Server 2008: Getting deadlocks... without any locks。
检查此q/a(http://stackoverflow.com/a/41594231/1158842)似乎是同一根本问题。如果您希望在SQL级别完成,那么您可能会前往sp_getapplock –
无需首先“选择”当前值。 'UPDATE Test_Table SET intCount = intCount + 1'就足够了。当你说“* it deadlocks *”时,你实际上是否因为SQL Server检测到死锁而导致一个事务被杀死的异常?如果是,那么请将该异常的错误消息添加到您的问题中。预计线程将等待,因为您不能同时更新多个事务中的同一行,第二个更新总是需要等待前一个完成。 –