没有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。
-
提交BeginExceuteNotQuery后,无法关闭连接。 它将中止执行。 删除使用块。
-
要关闭连接,您必须知道呼叫何时完成。 为此,您必须通常从回调中调用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的问题:
- 如果不调用EndExecuteNonQuery,BeginExecuteNonQuery将执行该过程,但是只要using子句处理了sql连接,操作就会被取消。 因此,这不合理。
- 如果通过使用委托调用BeginExecuteNonQuery,创建新线程等而不调用EndExecuteNonQuery,则可能会因内存泄漏而导致内存泄漏。 (稍后会详细介绍)。
- 在我们的测试中,调用存储过程而不是等待调用完成是不可能的。 无论多任务处理,某些地方都必须等待。
关于我们的解决方案:
参考: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表达式(无论需要多长时间)都会为您完成所有关闭操作。