没有EndExecuteNonQuery的BeginExecuteNonQuery

我有以下代码:

using (SqlConnection sqlConnection = new SqlConnection("blahblah;Asynchronous Processing=true;") { using (SqlCommand command = new SqlCommand("someProcedureName", sqlConnection)) { sqlConnection.Open(); command.CommandType = CommandType.StoredProcedure; command.Parameters.AddWithValue("@param1", param1); command.BeginExecuteNonQuery(); } } 

我从不调用EndExecuteNonQuery。

两个问题,首先是因为使用陈述还是其他任何原因阻止了这个问题? 第二,它会破坏什么吗? 像泄漏或连接问题? 我只是想告诉sql server运行一个存储过程,但我不想等待它,我甚至不关心它是否有效。 那可能吗? 谢谢阅读。

这不起作用,因为您在查询仍在运行时关闭连接。 执行此操作的最佳方法是使用线程池,如下所示:

 ThreadPool.QueueUserWorkItem(delegate { using (SqlConnection sqlConnection = new SqlConnection("blahblah;Asynchronous Processing=true;") { using (SqlCommand command = new SqlCommand("someProcedureName", sqlConnection)) { sqlConnection.Open(); command.CommandType = CommandType.StoredProcedure; command.Parameters.AddWithValue("@param1", param1); command.ExecuteNonQuery(); } } }); 

通常,当您调用Begin_Whatever_时,通常必须调用End_Whatever_或者您将泄漏内存。 此规则的一个重要例外是Control.BeginInvoke。

  1. 提交BeginExceuteNotQuery后,无法关闭连接。 它将中止执行。 删除使用块。

  2. 要关闭连接,您必须知道呼叫何时完成。 为此,您必须通常从回调中调用EndExecuteNonQuery:

 command.BeginExecuteNonQuery(delegate (IAsyncResult ar) { try { command.EndExecuteNonQuery(ar); } catch(Exception e) { /* log exception e */ } finally { sqlConnection.Dispose(); } }, null); 

如果要提交查询而不关心结果, 请参阅异步T-SQL执行以获得可靠模式,即使客户端出现连接或崩溃,也可确保执行。

您应该始终调用EndExecuteNonQuery()方法以防止泄漏。 它可能现在可以工作,但谁知道将来的.NET版本会发生什么。 一般规则总是遵循BeginExecute …与EndExecute …

我知道这是一个老post; 根据我们最近(非常确定的)实施和测试添加我的2c:D

回答OP的问题:

  1. 如果不调用EndExecuteNonQuery,BeginExecuteNonQuery将执行该过程,但是只要using子句处理了sql连接,操作就会被取消。 因此,这不合理。
  2. 如果通过使用委托调用BeginExecuteNonQuery,创建新线程等而不调用EndExecuteNonQuery,则可能会因内存泄漏而导致内存泄漏。 (稍后会详细介绍)。
  3. 在我们的测试中,调用存储过程而不是等待调用完成是不可能的。 无论多任务处理,某些地方都必须等待。

关于我们的解决方案:

参考:BeginExecuteNonQuery – > BENQ,EndExecuteNonQuery – > EENQ

使用案例:

我们有一个使用.Net TPL库的Windows服务(C#)。 我们需要根据服务选择的附加请求,在运行时使用存储过程从一个数据库加载数据到另一个数据库。 我们的存储过程使用try catch块进行内部事务和exception处理。

第一次尝试:

对于我们的第一次尝试,我们在此示例中实现了一个解决方案。在此示例中,您将看到MS选择调用BENQ,然后实现while循环以阻止执行,然后调用EENQ。 如果您不需要回调方法,则主要实现此解决方案。 这个解决方案的问题是只有BENQ对sql连接超时无知。 EENQ将超时。 因此,对于长时间运行的查询(希望是你使用BENQ的原因),你将陷入困境,一旦操作完成并且你调用EENQ,你将获得一个sql超时连接。

第二次尝试:

对于我们的第二次尝试,我们认为好,所以我们打电话给BENQ,然后添加一段时间,这样我们就不会关闭我们的sql连接而永远不会调用EENQ。 这有效,直到我们的存储过程中抛出exception。 因为我们从未调用过EENQ,所以操作从未完成,并且exception从未冒充我们的代码。 因此,我们永远陷入了循环/线程/内存泄漏。

第三次尝试:(解决方案)

对于我们的第三次尝试,我们打算打电话给BENQ,然后直接打电话给EENQ。 发生的事情是EENQ有效地阻止了线程中的执行,直到操作完成。 当存储过程中发生exception时,它被捕获。 当查询运行很长时,EENQ没有抛出超时exception,并且在所有情况下我们的sql连接对象都被处理掉了我们的线程。

以下是我们代码的一些摘录:

这里我们为调用存储过程的方法打开一个新线程。

 //Call the load data stored procedure. As this stored procedure can run longer we start it in its own thread. Task.Factory.StartNew(() => ClassName.MethodName(Parameters)); 

这是我们用来调用存储过程的方法中的代码。

 //Because this is a long running stored procedure, we start is up in a new thread. using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings[ConfigurationManager.AppSettings["ConnectionStringName"]].ConnectionString)) { try { //Create a new instance SqlCommand. SqlCommand command = new SqlCommand(ConfigurationManager.AppSettings["StoredProcedureName"], conn); //Set the command type as stored procedure. command.CommandType = CommandType.StoredProcedure; //Create input parameters. command.Parameters.Add(CreateInputParam("@Param1", SqlDbType.BigInt, Param1)); command.Parameters.Add(CreateInputParam("@Param2", SqlDbType.BigInt, Param3)); command.Parameters.Add(CreateInputParam("@Param3", SqlDbType.BigInt, Param3)); //Open up the sql connection. conn.Open(); //Create a new instance of type IAsyncResult and call the sp asynchronously. IAsyncResult result = command.BeginExecuteNonQuery(); //When the process has completed, we end the execution of the sp. command.EndExecuteNonQuery(result); } catch (Exception err) { //Write to the log. } } 

我希望这个答案能让人感到头疼:D我们已经彻底测试了这个问题并且没有遇到任何问题。

快乐的编码!

在这种情况下, using语句不是必需的,因为你应该自己手动关闭它而不是允许语法糖为你处理它(即在} )。 应该这么简单,以确保您没有泄漏。

    使用(SqlConnection sqlConnection = new SqlConnection(“blahblah; Asynchronous Processing = true;”)
     {
         using(SqlCommand command = new SqlCommand(“someProcedureName”,sqlConnection))
         {
             sqlConnection.Open();
             command.CommandType = CommandType.StoredProcedure;
             command.Parameters.AddWithValue(“@ param1”,param1);
             command.BeginExecuteNonQuery((ar)=>
             {
                 var cmd =(SqlCommand)ar.AsyncState;
                 cmd.EndExecuteNonQuery(AR);
                 cmd.Connection.Close();
             },命令);
         }
     }

正如您所看到的那样,命令完成后触发的lambda表达式(无论需要多长时间)都会为您完成所有关闭操作。