简体   繁体   English

C#中的SQL Server 2008:连接和命令对象

[英]SQL Server 2008 in C#: Connections and Command Objects

There's a lot of non-detailed questions on this one, so here goes. 关于这个问题有很多非详细的问题,所以这里有。

What is the best practice for connection handling in C# with SQL Server 2008? C#与SQL Server 2008中连接处理的最佳实践是什么? We have an assembly (which in our case is used by a WCF Service) that makes calls to an SQL Server. 我们有一个程序集(在我们的例子中由WCF服务使用),它调用SQL Server。 In general it seems like you need three objects to do this: The connection object, the command object, and the reader object. 通常,您似乎需要三个对象来执行此操作:连接对象,命令对象和读取器对象。

The only reliable way we've been able to get the calls to work is to do the following: 我们能够接听电话的唯一可靠方法是执行以下操作:

  1. Open the connection. 打开连接。
  2. Create the Command in a using() { } block 在using(){}块中创建命令
  3. Create the Reader to handle the response. 创建Reader以处理响应。
  4. Dispose of the reader. 处理读者。
  5. Implicitly dispose of the Command at the end of the using() block 在using()块的末尾隐式处理Command
  6. Close the connection. 关闭连接。

We ran into an unusual problem when running the same command multiple times iteratively, where it would complain that there was already a command or reader object attached to the connection that was still open. 当迭代地多次运行相同的命令时,我们遇到了一个不寻常的问题,它会抱怨已经有一个命令或读取器对象连接到仍然打开的连接。 The only rock solid solution was to close and reopen the connection with every command we did, iterative or just sequential (different commands.) 唯一坚如磐石的解决方案是关闭并重新打开与我们所做的每个命令的连接,迭代或只是顺序(不同的命令)。

So this is the question, since I come from a mysql_pconnect background on DB connection handling. 所以这是个问题,因为我来自数据库连接处理的mysql_pconnect背景。

  1. Is it going to significantly impact performance to be opening and closing a connection for each command? 是否会对每个命令打开和关闭连接的性能产生重大影响?
  2. If so for 1., what is the proper workaround, or code structure to handle serially repeating a command? 如果是这样,那么,处理串行重复命令的正确解决方法或代码结构是什么?
  3. Is there any way to reuse a connection, command or reader at all? 有没有办法重用连接,命令或阅读器?
  4. If not for 3., does this really impact performance or memory usage significantly (As in, our users would notice.) 如果不是3.,这是否会显着影响性能或内存使用(如我们的用户会注意到的那样。)

To answer point 1, if you look at the documentation for SqlConnection you'll see it explain about connection pooling. 要回答第1点,如果您查看SqlConnection的文档,您将看到有关连接池的说明。 This means that the SQL Server provider has a collection of connections readily available and each SqlConnection created simply gets the next available connection. 这意味着SQL Server提供程序具有一组可随时使用的连接,并且每个创建的SqlConnection只会获得下一个可用连接。 Therefore, to get the best performance, it is advisable to keep creating SqlConnection objects and using them for short operations and then disposing of them, thereby returning back to the connection pool. 因此,为了获得最佳性能,建议继续创建SqlConnection对象并将其用于简短操作然后处理它们,从而返回到连接池。

For point 3, I believe you can re-use an SqlConnection if you do SqlCommand.ExecuteNonQuery() , but if you use an SqlDataReader you cannot re-use the connection - it is tied to the SqlDataReader and must be closed/disposed of once finished. 对于第3点,我相信如果你执行SqlCommand.ExecuteNonQuery() ,你可以重用SqlConnection ,但是如果使用SqlDataReader就不能重用连接 - 它与SqlDataReader绑定,必须关闭/处理掉一次完了。

In addition to @PeterMonks answer: 除了@PeterMonks答案:

  1. The "expensive", unmanaged part of the SqlConnection is re-used by the provider (connection pooling) as long as you use the same connection string. 只要您使用相同的连接字符串,提供程序(连接池)就会重复使用SqlConnection的“昂贵”非托管部分。 So while there is a small overhead to creating a new managed wrapper each time, it isn't actually a 1:1 relationship with creating connections to the SQL server instance, so it isnt as expensive as you might think. 因此,虽然每次创建新的托管包装器的开销很小,但实际上与创建与SQL Server实例的连接并不是1:1的关系,因此它并不像您想象的那么昂贵。

  2. To serially repeat a command that returns a data reader, you must a) always execute the command on the same thread (commands are not thread safe) and b) Close() or Dispose() the DataReader instances before creating the next one. 要连续重复返回数据读取器的命令,您必须a)始终在同一线程上执行命令(命令不是线程安全的)和b)在创建下一个实例之前Close()Dispose() DataReader实例。 You can do that by putting the DataReaders in a using block as well. 您可以通过将DataReaders放在using块中来实现。

Here is how you put the reader into a using block: 以下是将阅读器放入使用块的方法:

using (var dr = myCommand.ExecuteReader(...)) {
    // Previous discussions have indicated that a close in here, 
    // while seemingly redundant, can possibly help with the error 
    // you are seeing.
    dr.Close();
}

Another useful technique, as @DavidStratton mentions, is to enable MARS, but be aware that there is overhead associated with keeping resultsets open- you still want to close your readers as soon as you are done with them, because unclosed, undisposed readers do represent significant resource allocations on the server and the client. 正如@DavidStratton所提到的,另一个有用的技术是启用MARS,但要注意保持结果集打开会产生开销 - 你仍然希望在完成它们后立即关闭你的读者,因为未封闭的,不存在的读者确实代表服务器和客户端上的重要资源分配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM