SqlConnection/SqlCommand是线程安全的吗?

6
我正在创建一个WCF Web服务。作为其任务的一部分,它将不幸需要执行一些相当复杂的计算,但这些计算可以在调用WebService之间共享。实际上,我们只需要做一次计算,以后的所有调用都可以受益。
然而,由于WCF没有共享应用程序状态,所以将WCF设置为单实例模式似乎是合理的。(每个客户端都可能需要所有计算,迫使我们针对每个会话重新计算,这可能是可行的,或者每个调用都要重新计算,这是无法接受的)
然而,我对多线程代码的安全性并不很熟悉。我已经阅读了一些相关资料,因为我们的WCF代码没有写入共享状态(除了计算位,这很容易保护),我几乎相信我不需要改变任何东西。
然而,有一个问题 - 我们使用SqlConnection和SqlCommand与我们的后端进行通信,我不确定这些是否是线程安全的?
编辑:我应该明确的是,Commands / Connections始终局限于方法中。我们在谈论以下模式:
using sqlConn = new SqlConnection(...) {
 try {
  sqlConn.Open()
} catch () {
  throw new FaultException();
}
var cmd = new SqlCommand("Some SQL", sqlConn);
var reader = cmd.ExecuteReader();
//Read the stuff 
reader.Close();
//Return something
}

我在MSDN上查询了SqlCommand类:http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.aspx,其中写道:“任何此类型的公共静态成员(Visual Basic中为Shared)都是线程安全的。任何实例成员都不能保证是线程安全的。”

我的理解是,MS没有保证SqlCommand能在多线程场景下正常工作,您是否也这样认为?

如果不支持,是否有线程安全的替代方案?

是的,我可以在WebService中锁定所有数据库访问方法,但这很麻烦,而且如果不必要,我宁愿不这样做 :)

提前感谢您的回复!

END EDIT


如果您在线程之间不共享相同的实例,并且类的静态部分是线程安全的,则您就没有问题。 - Rune FS
1
请勿跨线程共享这些实例,打开它们,运行您的查询,并尽快处理。连接池将处理连接优化。 - TheCodeKing
3个回答

12
我是否正确地理解了这句话的意思,即微软不保证SqlCommand在多线程情况下工作?只要使用正确,它就能在多线程场景中正常工作。如果多个线程尝试使用相同的SqlCommand,你认为会发生什么?它怎么可能正常工作呢?但是,如果不同的线程使用不同的连接向同一个数据库发出不同的命令,那就没有问题。MSDN上关于线程安全的注释真的很糟糕,措辞不当,一定是由一个不懂什么是线程安全的人编写的。他们试图用那条信息(附加在99.9%的类和函数文档上)表达的意思是:“任何此类型的静态方法都可以被多个线程同时调用。如果同时通过多个线程调用同一实例成员,则不能保证其安全性,但访问不同对象上的同一成员则完全没问题。”

同意 - 多个线程使用相同的SqlCommand永远不会起作用。 我不确定的是,是否安全让“不同的线程使用不同的连接向同一个数据库发出不同的命令”,正如你所说。基本上,我怎么知道SqlCommand没有一些疯狂的内部静态状态会成为问题呢?即使我写这篇文章时,我意识到这听起来有多愚蠢...所以,谢谢你的回答!我的代码应该没问题 :-) - Fafnr
@jalf。不同的线程发出不同的命令,但使用一个静态单例连接怎么样?我发现这个方法可行,但怀疑在某些情况下可能会出问题。 - Abubakar Mehmood

3

我不确定你同时想要使用SqlCommand做什么,但无论内部线程安全性如何,你肯定会遇到问题,因为使用SqlCommand需要它维护状态,例如:

SqlCommand cmd = myConnection.CreateCommand();
cmd.CommandText = "......";
cmd.Parameters.Add(.....);
cmd.ExecuteNonQuery();

如果你想通过多线程共享同一个命令,那么在使用时必须锁定某些内容。至于SqlConnection,它只允许同时开放单个查询,所以如果你正在使用DataReaders,那么你需要再次锁定一些内容。如果要同时运行多个任务,则使用多个连接/命令至关重要。
另外,当你说WCF没有共享应用程序状态时,我并不确定你的意思 - 这并不一定是真的,它将取决于如何托管WCF应用程序。如果它是在IIS下托管的WCF服务,且设置了" aspNetCompatibilityEnabled="true",则仍然会有类似网站中的Application对象。如果您不使用aspNetCompatibility,还有其他选项。

我意识到我表达得不够清楚,所以我更新了一个我尝试做的例子...我不会在方法调用之间共享命令/连接。我总是在每个方法中新建命令/连接。我不确定的是它们内部是否有一些结构会让我感到困扰。我不知道aspNetCompatibilityEnabled,谢谢你告诉我!我对如何明智地构建这个项目非常不确定,有时候向那些做这些事情更久的人请教真的很有帮助 :-) - Fafnr

2

只需在一个线程中使用连接和命令,不必担心应用程序级线程问题。 SQL Server足以处理并发,无需在代码中锁定。.Net连接池也可以快速检索有效连接。

我并不是说您制作的整个WCF层都不需要关注线程,但其数据访问层必须依赖于数据库锁而不是.NET锁。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接