连接未关闭,连接当前状态为打开。

9

如何解决我的函数中出现的“连接已关闭”问题:

SqlConnection con=new SqlConnection(@"Here is My Connection");

public void run_runcommand(string query)   
{   

    try   
    {   
        con.Open();   
        SqlCommand cmd1 = new SqlCommand(query, con);   

        cmd1.ExecuteNonQuery();    
        con.Close();    
    }    
    catch (Exception ex) { throw ex; }                        
}    
//...
try       
{           
    string query="my query";           
    db.run_runcommand(query);          
}         
catch(Exception ex)            
{         
    MessageBox.Show(ex.Message);              
}

20
顺便说一下,那个 catch(Exception ex) { throw ex; } 没有任何好处,反而可能会带来很多坏处。 - Marc Gravell
8
为了保留堆栈跟踪信息,你应该使用 throw 而不是 throw ex。 - Camilo Sanchez
5个回答

29

我假设错误是在这一行引发的:

con.Open(); // InvalidOperationException if it's already open

由于您正在重复使用连接,而且上一次可能还没有关闭连接。

您应该立即关闭连接,最好使用using语句

public void run_runcommand(string query)   
{
    using(var con = new SqlConnection(connectionString))
    using(var cmd = new SqlCommand(query, con))
    {
        con.Open();
        // ...
    }  // close not needed since dispose also closes the connection
}

请注意,不要仅仅为了重新抛出异常而使用Catch块。如果你对它没有任何操作,请完全不要捕获它。最好使用throw;而不是throw ex;以保留堆栈跟踪。https://dev59.com/x2445IYBdhLWcg3wpL1_#4761295


con.close() 需要。我会尝试以上两个代码,但当我的查询第二次执行时仍会出现错误,否则第一次不会显示错误。 - Naeem Shah
@NaeemShah:那么你的方法中没有使用using来创建连接。因此,当您第二次调用该方法时,连接将首先被创建,然后打开。 - Tim Schmelter

13

建议您编写finally块,并在其中使用con.close(),无论您在try catch块中的哪里使用它。

例如:

public void run_runcommand(string query)   
{   
    try   
    {   
        con.Open();   
        SqlCommand cmd1 = new SqlCommand(query, con);   

        cmd1.ExecuteNonQuery();    
        con.Close();    
    }    
    catch (Exception ex)
    {
       throw ex; //TODO: Please log it or remove the catch
    }
    finally
    {
       con.close();
    }

}


try       
{           
    string query="my query";           
    db.run_runcommand(query);          
}         
catch(Exception ex)            
{         
    MessageBox.Show(ex.Message);              
}   
finally
{
   con.close();
}

1
然而,using-statement 就像 finally-block 一样。因此这并没有什么区别。 - Tim Schmelter
@TimSchmelter:我从未在我的项目中使用过using语句。那么,using语句会自动关闭连接吗? - Freelancer
@自由职业者:是的,这就是我在我的答案中想要表达的意思(“你应该立即关闭连接,最好使用using语句:”)。所以using只是在最后调用dispose(即使出现异常的情况下也是如此)。连接dispose时肯定会关闭。实际上,对于每个实现IDisposable的对象都使用using是一个好习惯,因为它可能包含未管理的资源(例如,您的SqlCommand)。 - Tim Schmelter
我尝试使用语句,但仍然出现了这个错误:连接未关闭,连接的当前状态为打开。我以为使用语句应该会将其关闭? - user1663380
在执行每个 SQL 语句之前,我会检查连接是否正常,使用语句 then try { connectionStr.Open()}catch(Exception){}。 - user1663380
显示剩余2条评论

11

在打开连接之前检查连接状态:

if (con.State != ConnectionState.Open)
    con.Open(); 

4

除了已经给出的答案,我会检查它是否只是打开状态,而是连接状态,并在连接状态下等待。

if (con.State != ConnectionState.Open && con.State != ConnectionState.Connecting) {
    con.Open();
}
var attempts = 0;
while (con.State == ConnectionState.Connecting && attempts < 10) {
    attempts++;
    Thread.Sleep(500);
}

当然,如果你希望确保连接关闭,那么在try之后,你还需要将con.Close()放在finally块中,因为发生异常后的finally块外的任何代码都不会运行。
另外,在throw时,你不需要throw ex,你可以直接使用throw;。通过throw ex你会破坏堆栈跟踪信息。
更新:我看到你在tryfinally中都有con.Close(),这样会一直报错,因为如果try块正常工作,它将关闭连接,然后进入finally块,无论是否出现错误,都会尝试关闭已经关闭的连接。同时要注意大小写问题——Close()close()不是相同的函数,只有一个调用了该函数,另一个将产生错误。
你需要从try块中移除close函数,并仅将其留在finally块中。

2

您的连接字符串已打开。 您可以使用代码来检查它:

if(cmd.Connection.State != ConnectionState.Open) cmd.Connection.Open();

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