我在 WinForm 项目上有一个 C# 无限循环代码,它使用 SQL 中的一个值,该值在 1/0 之间交替,如果它是 0,它将继续该过程,而如果它是 1,它将留在循环中。这段代码的目的是为了防止多个人处理X。
我的问题是,如果我有多个用户使用该程序,并且其中一些用户同时按下按钮来运行该进程,则循环无法捕获已经有人在处理 X。
我认为问题是所有用户都在读取 SQL 值,然后他们才有机会将 SQL 中的值更新为 1,并阻止其他用户继续该过程。
有办法解决这个问题吗?
这是循环的示例代码:
SqlDataReader VerifyIfBusyReader = null;
SqlCommand VerifyIfBusy = new SqlCommand("SELECT [Value] FROM [Variables] WHERE [TYPE] = 'IsBusy'", CONNECTION);
int verify = 1;
int counts = 0;
int milliseconds = 2000;
while (verify == 1)
{
counts++;
if (counts == 30)
{
break;
}
VerifyIfBusyReader = VerifyIfBusy.ExecuteReader();
VerifyIfBusyReader.Read();
if (int.Parse(VerifyIfBusyReader[0].ToString()) == 1)
{
VerifyIfBusyReader.Close();
}
else if (int.Parse(VerifyIfBusyReader[0].ToString()) == 0)
{
verify = 0;
VerifyIfBusyReader.Close();
}
Thread.Sleep(milliseconds);
}
SqlCommand IsBusyNow = new SqlCommand("UPDATE [Variables] SET [VALUE] = 1 WHERE [TYPE] = 'IsBusy'", CONNECTION);
VerifyIfBusyReader = IsBusyNow.ExecuteReader();
VerifyIfBusyReader.Close();
如有任何帮助,我们将不胜感激。
当然,我还有另一个函数,可以在 SQL 完成后将其更新回 0,但这不是这里的问题。
在获取不忙结果和设置它之间存在竞争条件。
您可以将
UPDATE
与 OUTPUT
一起使用,这将是原子的。循环直到得到结果。
请注意,如果您不应该获得结果集,那么您应该使用
ExecuteNonQuery
,对于单个结果,您可以使用 ExecuteScalar
。
async
using
进行处置。for
循环,而不是 while
。using (var conn = new SqlConnection(ConnStringHere))
{
using SqlCommand SetBusyOrNull = new SqlCommand(@"
UPDATE Variables
SET VALUE = 1
OUTPUT inserted.VALUE
WHERE TYPE = 'IsBusy'
AND VALUE = 0;
", conn);
int counts = 30;
int milliseconds = 2000;
for (var i = 0; i < counts; i++)
{
await conn.OpenAsync();
var isSet = (await VerifyIfBusy.ExecuteScalarAsync()) as int? == 1;
await conn.CloseAsync();
if (isSet)
return true;
await Task.Delay(milliseconds);
}
throw new Exception($"Still busy after {counts} tries");
// alternatively return false;
}