我编写了多线程应用程序,每个线程调用一个sql server程序..我需要保护一行不被多个线程获取我希望每一行只用一个线程我用这个代码:< / p>
CREATE PROCEDURE GetRow
@ThreadID int
AS
BEGIN
DECLARE @rowID int;
SELECT TOP (1) @rowID=[ID] FROM [TestTable] WHERE [ThreadID] = 0 (AND some other parameters)
IF @rowID is not NULL
BEGIN
UPDATE TOP (1) [TestTable] SET [CallCount] = [CallCount]+1,[ThreadID] = @ThreadID WHERE [ID] = @rowID
--some other codes
END
END
正如我所说,我运行应用程序,然后我的应用程序创建10个线程,我设置threadid只用一个线程,但我看到一行调用超过1个线程,大约4-5个线程得到一行。我怎么能以最好的方式做到这一点,我通过这个代码解决了它,我不想在选择和更新中有两个相同的地方:
CREATE PROCEDURE GetRow
@ThreadID int
AS
BEGIN
DECLARE @rowID int;
UPDATE TOP (1) [TestTable] SET [CallCount] = [CallCount]+1,[ThreadID] = @ThreadID WHERE [ThreadID] = 0 (AND some other parameters)
SELECT TOP (1) @rowID=[ID] FROM [TestTable] WHERE [ThreadID] = @ThreadID (AND some other parameters)
IF @rowID is not NULL
BEGIN
--some other codes
END
END
如何使用热门代码执行此操作?我应该先更新,然后选择上面的代码进行修复吗?
答案 0 :(得分:2)
如果您使用的是SQL Server 2005或更高版本,则可以combine the UPDATE
and SELECT
使用新的OUTPUT
clause。
但是,我建议您备份并考虑您的数据库架构,以及它是否真的适合您的问题 - 尤其是多线程!
我得到你想要计算每个帖子的来电的印象。将每个INSERT
行调用到一个只有一个ThreadCallCount
列的简单ThreadID
表中会更好。每次通话都是新的一行。稍后您可以通过Sum()
ThreadID
此表来获取每个主题的总调用次数。这很简单,也很容易确保它的线程安全。
听起来你正在尝试检索其他一些数据,并且不清楚它是如何/何时存储的。但是类似的分析 - 以及更简单的表格 - 可能会帮助你。
一般情况下:不要觉得你需要将它们全部挤在一张桌子上。使用多线程,它将有助于将事物分解成更小的部分。随意使用更多的桌子,每个桌子都有一个明确的目的。 SQL Server旨在安全有效地处理行事务,因此尽量利用它。
答案 1 :(得分:1)
我建议编写thead安全代码而不是在存储过程中执行此操作。
您没有提及您的编码语言,在C#中,一种方法是将调用此存储过程的代码包装在lock
块中:
using System.Threading
...
public class ClassName {
object syncLock = new object();
...
SomeFunction(){
lock(syncLock){
// For example, com could be SqlCommand object that calls stored procedure
int updatedRowCount = com.ExecuteNonQuery();
...
}
}
}