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

本文关键字:SqlConnection 对象 挂起 我的 应用程序 为什么 | 更新日期: 2023-09-27 18:31:46

我正在尝试从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放在 using 块中也会导致应用程序挂起,除非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 万行,但由于我只获取架构信息,我认为这不是问题。 我的问题是:为什么我的应用程序在尝试关闭连接时卡住?

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

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.

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

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

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。

总的来说,

它看起来是正确的,我认为你需要一点优化。除了上述关于避免使用DataReader的建议之外,我建议使用连接池。您可以从这里获取详细信息:

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

你能试试这个吗?

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设置FMTONLY似乎是要走的路

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

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

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

看看这个参考资料:

  • 数据库.表属性
  • 表类

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

  • 使用 SMO 检索 SQL Server 2005 数据库信息:数据库信息、表信息

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

我会尝试这样的事情。 这可确保清理所有项目,并避免使用 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);
    }