为什么我的应用程序在尝试关闭SqlConnection对象时挂起?

时间:2012-04-18 21:24:40

标签: c# sql sql-server ado.net

我试图从SQL Server上的SQL表中获取C#中的列信息。我正在关注此链接中的示例:http://support.microsoft.com/kb/310107我的程序在尝试关闭连接时奇怪地挂起。如果未关闭连接,程序将退出而不会出现任何异常。这是我的代码:

SqlConnection connection = new SqlConnection(@"MyConnectionString"); 
connection.Open();
SqlCommand command = new SqlCommand("SELECT * FROM MyTable", connection);
SqlDataReader reader = command.ExecuteReader(CommandBehavior.KeyInfo); // If this is changed to CommandBehavior.SchemaOnly, the program runs fast.
DataTable table = reader.GetSchemaTable();
Console.WriteLine(table.Rows.Count);
connection.Close(); // Alternatively If this line is commented out, the program runs fast.

SqlConnection置于使用区块内也会导致应用程序挂起,除非CommandBehavior.KeyInfo更改为CommandBehavior.SchemaOnly

using (SqlConnection connection = new SqlConnection(@"MyConnectionString"))
{
    connection.Open();
    SqlCommand command = new SqlCommand("SELECT * FROM MyTable", connection);
    SqlDataReader reader = command.ExecuteReader(CommandBehavior.KeyInfo); // If this is changed to CommandBehavior.SchemaOnly, the program runs fast even here in the using
    DataTable table = reader.GetSchemaTable();
    Console.WriteLine(table.Rows.Count);
}

有问题的表有超过300万行,但由于我只获取了Schema信息,我认为这不是问题。我的问题是:为什么我的应用程序在尝试关闭连接时会卡住?

解决方案:也许这不是最优的,但确实有效;我在连接上调用command.Cancel();之前插入了Close语句:

SqlConnection connection = new SqlConnection(@"MyConnectionString"); 
connection.Open();
SqlCommand command = new SqlCommand("SELECT * FROM MyTable", connection);
SqlDataReader reader = command.ExecuteReader(CommandBehavior.KeyInfo); // If this is changed to CommandBehavior.SchemaOnly, the program runs fast.
DataTable table = reader.GetSchemaTable();
Console.WriteLine(table.Rows.Count);
command.Cancel(); // <-- This is it.
connection.Close(); // Alternatively If this line is commented out, the program runs fast.

5 个答案:

答案 0 :(得分:7)

很久以前,我看到过类似的东西。对我来说,这是因为我做了类似的事情:

SqlCommand command = new SqlCommand("SELECT * FROM MyTable", connection);
SqlDataReader reader = command.ExecuteReader();

// here, I started looping, reading one record at a time
// and after reading, say, 100 records, I'd break out of the loop

connection.Close();  // this would hang

问题是该命令似乎想要完成。也就是说,浏览整个结果集。我的结果集有数百万条记录。它最终会完成。

我在调用command.Cancel()之前添加了对connection.Close()的调用来解决问题。

有关详细信息,请参阅http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=610

答案 1 :(得分:0)

总的来说,我认为你需要一点优化。除了上述有关避免DataReader的建议外,我还建议使用连接池。您可以从这里获得详细信息:

http://www.techrepublic.com/article/take-advantage-of-adonet-connection-pooling/6107854

答案 2 :(得分:0)

你可以尝试一下吗?

DataTable dt = new DataTable(); 
using(SqlConnection conn = new SqlConnection("yourConnectionString"))
{
    SqlCommand cmd = new SqlCommand("SET FMTONLY ON; " + yourQueryString + "; SET FMTONLY OFF;",conn);  
    conn.Open(); 
    dt.Load(cmd.ExecuteReader()); 
}
来自MSDN的

SET FMTONLY ON/OFF似乎要走了

答案 3 :(得分:0)

有一种特定的方法可以做到这一点,使用SMO(SQL Server管理对象)

您可以获取数据库中的表集合,然后读取您感兴趣的表的属性(列,键和所有可以想象的属性)

这是SSMS用于获取和设置所有数据库对象的属性的内容。

看看这个参考文献:

这是如何获取表属性的完整示例:

这将允许您以非常简单的方式从数据库中获取所有可能的信息。 VB.NET和C#中有很多样本。

答案 4 :(得分:0)

我会尝试这样的事情。这可以确保清理所有项目 - 并避免使用DataReader。除非您有异常大量的数据导致内存问题,否则不需要此操作。

  public void DoWork(string connectionstring)
    {
        DataTable dt = new DataTable("MyData");
        using (var connection = new SqlConnection(connectionstring))
        {
            connection.Open();
            string commandtext = "SELECT * FROM MyTable";

            using(var adapter = new SqlDataAdapter(commandtext, connection))
            {
                adapter.Fill(dt);
            }
            connection.Close();
        }
        Console.WriteLine(dt.Rows.Count);
    }