我有以下代码:
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运行一个存储过程,但我不想等待它,我甚至不关心它是否有效。那可能吗?谢谢你的阅读。
答案 0 :(得分:24)
这不起作用,因为您在查询仍在运行时关闭连接。执行此操作的最佳方法是使用线程池,如下所示:
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 :(得分:11)
提交BeginExceuteNotQuery后无法关闭连接。它将中止执行。删除使用块。
要关闭连接,您必须知道通话何时完成。为此你必须调用EndExecuteNonQuery,通常来自回调:
command.BeginExecuteNonQuery(delegate (IAsyncResult ar) {
try { command.EndExecuteNonQuery(ar); }
catch(Exception e) { /* log exception e */ }
finally { sqlConnection.Dispose(); }
}, null);
如果您想提交查询而不关心结果,请see Asynchronous T-SQL execution获取可靠模式,以确保即使客户端出现连接或崩溃也能执行。
答案 2 :(得分:5)
您应始终调用EndExecuteNonQuery()方法以防止泄漏。它可能现在可以工作,但谁知道在未来的.NET版本中会发生什么。一般规则始终遵循BeginExecute ...使用EndExecute ...
答案 3 :(得分:3)
我知道这是一个老帖子;根据我们最近(非常确定的)实施和测试添加我的2c:D
回答OP的问题:
关于我们的解决方案:
参考:BeginExecuteNonQuery - > BENQ,EndExecuteNonQuery - > EENQ
使用案例
我们有一个使用.Net TPL库的Windows服务(C#)。我们需要根据服务选择的附加请求,在运行时使用存储过程从一个数据库加载数据到另一个数据库。我们的存储过程有一个内部事务和使用try catch块的异常处理。
首先尝试:
我们第一次尝试在这个例子中实现了一个解决方案MS Solution,你会看到MS选择调用BENQ然后实现一个while循环来阻止执行,然后调用EENQ。如果您不需要回调方法,则主要实现此解决方案。这个解决方案的问题是只有BENQ对sql连接超时无知。 EENQ将超时。因此,对于长时间运行的查询(希望是你使用BENQ的原因),你会陷入困境,一旦操作完成并调用EENQ,你将获得一个sql超时连接。
第二次尝试:
对于我们的第二次尝试,我们认为好,所以我们打电话给BENQ,然后添加一段时间,这样我们就不会关闭我们的sql连接而永远不会调用EENQ。这有效,直到我们的存储过程中抛出异常。因为我们从未调用过EENQ,所以操作从未完成,并且异常从未冒充我们的代码。因此,我们永远陷入了循环/线程/内存泄漏。
第三次尝试:(解决方案)
对于我们的第三次尝试,我们打算打电话给BENQ,然后直接打电话给EENQ。发生的事情是EENQ有效地阻止了线程中的执行,直到操作完成。当存储过程中发生异常时,它被捕获。当查询运行很长时,EENQ没有抛出超时异常,并且在所有情况下我们的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我们已经对此进行了彻底的测试,并且没有遇到任何问题。
快乐的编码!
答案 4 :(得分:0)
在这种情况下,using
语句不是必需的,因为您应该自己手动关闭它而不是允许语法糖为您处理它(即在}
)。
应该这么简单,以确保您没有泄漏。
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(); }, command); } }正如您所看到的,在命令完成后触发的lambda表达式(无论需要多长时间)都可以为您完成所有关闭。