C# SQL和C的线程问题,其中不同的线程获得相同的数目,但不应为';T
我的场景:表中有n个记录,线程试图访问该表。一个人必须得到第一个号码并删除它,其他人必须一个接一个地得到第二个、第三个等等 但问题是一些线程得到了相同的数目。我如何避免这种情况 我的代码:C# SQL和C的线程问题,其中不同的线程获得相同的数目,但不应为';T,c#,sql,C#,Sql,我的场景:表中有n个记录,线程试图访问该表。一个人必须得到第一个号码并删除它,其他人必须一个接一个地得到第二个、第三个等等 但问题是一些线程得到了相同的数目。我如何避免这种情况 我的代码: private void Form1_Load(object sender, EventArgs e) { for (int j = 1; j >= 10; j++) { Thread.Sleep(1000); ThreadStart StarterCon
private void Form1_Load(object sender, EventArgs e)
{
for (int j = 1; j >= 10; j++)
{
Thread.Sleep(1000);
ThreadStart StarterCon = delegate { this.Start_new(sno); };
Thread th = new Thread(StarterCon);
th.Start();
}
}
private void Start_new(int h)
{
try
{
for (; ; )
{
using (SqlConnection ObjConn = new SqlConnection(ConnectionString))
{
ObjConn.Open();
using (SqlDataAdapter ObjAda = new SqlDataAdapter("Select_BlockedNubmer", ObjConn))
{
ObjAda.SelectCommand.CommandType = CommandType.StoredProcedure;
SqlParameter parm;
parm = ObjAda.SelectCommand.Parameters.Add("@id", SqlDbType.NVarChar);
parm.Value = h;
using (DataTable dtTable = new DataTable())
{
ObjAda.Fill(dtTable);
}
}
ObjConn.Close();
}
Thread.Sleep(500);
}
}
catch { }
}
我的存储过程是
Create procedure [dbo].[Select_BlockedNubmer]
@id varchar(max)
as
begin
set rowcount 1
select * from BlockedNumber
delete from BlockedNumber
set rowcount 0
end
编辑:我尝试了以下存储过程。它工作正常,但读取数字非常慢:
ALTER procedure [dbo].[Select_BlockedNubmer]
@id varchar(max)
as
begin
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
begin transaction
set rowcount 1
select * from BlockedNumber
delete from BlockedNumber
set rowcount 0
commit transaction
end
你应使用:
事务确保两个线程无法访问数据的“中间”状态。假设你是线程X:你选择一个数字。一旦你这么做,这个号码就属于你,没有其他线程可以读取它。所有其他线程都必须等待您提交事务,然后才能读取它们的事务。这使您有机会在提交事务之前删除该号码,这样他们就不会看到它。您将永远循环。在这个循环中,您反复执行一些非常昂贵的操作,这可能会导致太多的连接或其他奇怪的东西四处浮动 我的建议是:只创建一个
SqlConnection
对象。不要每0.5秒循环一次,而是减慢循环速度或对外部触发器作出反应。您还可以重用SqlDataAdapter
对象以获得更好的性能
对于线程,可以使用lock
或使用其他同步原语来防止争用情况。虽然所用库方法上的单个静态方法是线程安全的,但这并不意味着在调用它们之间,线程会干扰数据对象
更新:已编辑,因为一开始线程代码是模糊的。如果您试图不加区分地选择和删除记录,并且看起来是这样,为什么不更改存储过程?返回所有记录,然后删除所有记录?为什么您需要选择1/delete 1(或者对于代码示例,选择1/delete all)的约束?你想完成什么?事实上,直到现在我才注意到:你的第一个循环从未执行过
j>=10
始终为false。。。你曾经运行过你的代码吗?哦,sno
应该包含什么?这可能与“线程获得相同的编号”有关,存储过程中的@id
似乎也未使用☺@Timwi:(在你之前的sno
评论中):事实上,这个变量可能是问题的根源(紧挨着没有同步的线程)。@Abel:Mwahaha,我也可以编辑!:-DHm,不能代表下层选民说话,但公平地说,他没有流动的联系:他适当地处理了他们。@Timwi:这是正确的,但正如你所知,Dispose
是一回事,但托管资源不会在处理时被清除,而是在下一个GC循环时被清除。此外,设置SqlConnection是一项非常昂贵的操作,可能需要数十或百分之一毫秒才能完成。它们根本不属于内部循环。最后,这是一个猜测,SqlConnection
在内部使用池,当一次创建百分之一百的连接时,这可能会完全混淆,但这是一个猜测。@Timwi:haha,ahum,好吧,那么,数百,tx@anbuselvanmca:代码中存在的问题不仅仅是事务。请参阅原始问题下方的评论。并花一些时间更新代码以反映您当前的情况,因为这不可能是准确的。在SQL2005及更高版本上,您不需要使用显式事务:DELETE TOP(1)FROM BlockedNumber OUTPUT DELETED.
将完成此任务。还有一个额外的好处是,它修复了不完整的语义,这意味着您的SELECT
和DELETE
可能引用不同的行,因为没有明确的排序或筛选。
Create procedure [dbo].[Select_BlockedNubmer]
@id varchar(max)
as
begin
begin transaction
set rowcount 1
select * from BlockedNumber
delete from BlockedNumber
set rowcount 0
commit transaction
end