共享的SqlConnection

6
在.NET应用程序中,是否将所有数据库连接都使用一个共享的SqlConnection对象是一个好的实践,还是每次访问数据库时都应该有一个单独的对象?我目前使用的是共享的SqlConnection对象,但突然遇到了问题。当我需要使用SQL身份验证模式而不是Windows身份验证模式时,似乎不能使用共享的对象。我第一次尝试使用SQL身份验证,当我尝试第二次使用同一连接时,它给了我这个错误消息:“此命令关联了一个必须首先关闭的已打开的DataReader。”请帮忙解决。
6个回答

6

你真的应该有一个单独的连接。重用连接可以使用连接池来处理。像其他人所说的那样,第二个问题可能可以通过启用MARS来解决。


3
那个错误与身份验证完全无关。在关闭从ExecuteReader()返回的SqlDataReader之前,您正在重用中间的连接。这是被禁止的。您必须检查代码并消除问题。有使用MARS(多活动记录集)的替代方法,但我强烈反对。
在应用程序中使用多个连接可能会更糟,因为显然您不知道哪些连接正在使用以及何时使用,因此当您使用单独的连接时,您将遇到事务一致性问题。

如果你说“不要使用MARS” - 你有具体的原因吗?出于好奇... - Marc Gravell
http://blogs.msdn.com/sqlnativeclient/archive/2006/09/27/774290.aspx讨论了使用MARS的一些负面影响。 - RichardOD
2
MARS 的事务隔离模型是不完整的,理论上没有完全定义。结果是服务器可能会变得“困惑”,正如 Richard 发布的链接所承认的那样。通常情况下,“混淆”意味着可能的交互数量太大,服务器中并未测试和验证所有代码路径。 - Remus Rusanu
2
只是补充一下这个错误是如何发生的:你要么在一个SqlDataReader循环中显式调用了新的批处理(不太可能,因为你以前应该见过这种情况),要么你忽略了SqlDataReader.Close调用,很可能是由于异常(可能与安全性变化有关)。始终使用using语句包装你的SqlDataReader,在出现异常时强制其关闭。 - Remus Rusanu

2
很多内容可能与此处重复。简而言之,在大多数情况下,保持连接短暂和本地化。关于数据读取器,也许启用MARS

2
你的问题在于你试图使用一个当前被SqlDataReader使用的连接,这是不允许的。当你使用SqlDataReader时,必须在重新使用正在被消耗的连接之前先将其关闭。我建议你每次访问数据库时创建不同的连接(任何时候都可以,不仅限于SqlDataReaders)。如果启用了连接池,则框架本身(或者是SqlServer?)将在可能的情况下重用连接。
如果你需要按顺序访问数据库,比如说你先做一个查询,然后再做另一个查询,最后是一个更新操作,那么你可以重用连接(我的意思是,使用同一个SqlConnection实例),但是如果你需要在读取SqlDataReader的同时访问数据库,则需要使用2个不同的连接。
当然,你必须牢记并发问题。如果你使用事务,那么在某些操作期间可能会锁定某些记录,而当你与其他查询并行使用SqlDataReader时,应该将隔离级别设置为不会影响其他查询的级别。

1

对于单个线程而言,使用单个SqlConnection对象可能会表现更好,但它会对你的数据库服务器这一宝贵资源提出要求,因为它会保持连接,从而比必要时间更长地占用db服务器资源。

最好尽可能短暂地实例化SqlConnection。连接池可以减轻大部分设置连接的开销,并确保最有效地利用数据库资源。


0
如果你正在使用 SQL Server 2000,this 可能会回答你的问题。
那里获胜的答案似乎是“这是由于 MARs 的默认设置发生了更改。它以前是默认开启的,但在 RC1 后,我们将其更改为默认关闭。因此,只需更改连接字符串以添加它(在连接字符串中添加 MultipleActiveResultSets=True)。”

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