从Windows窗体异步执行存储过程然后断开连接?

时间:2009-08-04 19:28:12

标签: c# sql-server-2005 stored-procedures asynchronous

我正在从我的应用程序调用存储过程,可能需要30分钟才能执行。

我不想让我的用户在整个时间段内打开应用程序。所以我想调用sproc,让它飞起来,让他们关闭应用程序并稍后再回来。

我该怎么做?

8 个答案:

答案 0 :(得分:26)

这实际上是一种非常常见的情况。你不能做任何基于客户端的事情,因为客户可能会离开并断开连接,你将失去迄今为止所做的工作。解决方案是使用Service Broker Activation:您在数据库中创建服务并附加激活的过程。在您的应用程序(或ASP页面)中,您向服务发送消息并为您的过程嵌入必要的参数。应用程序提交后,该消息将激活服务过程。服务过程从消息中读取参数并调用您的过程。由于激活发生在与原始连接无关的服务器线程上,因此这是可靠的。实际上,服务器甚至可以在执行过程时关闭并重新启动,并且工作将被回滚然后恢复,因为激活消息将在重新启动后再次触发服务过程。

<强>更新

我已经发布了有关如何执行此操作的详细信息,包括我博客上的示例代码:Asynchronous procedure execution

答案 1 :(得分:3)

您可以使用SqlCommand的{​​{3}}方法(取决于它是否返回结果),并传递回调委托。

答案 2 :(得分:2)

我建议重新架构。创建一个“工作队列”表,您可以在其中记录运行存储过程的请求。然后要么有Windows服务或SQL Server作业不时检查工作队列(或者真的很巧妙并使用触发器)来启动存储过程。让存储过程不时在工作队列表中更新进度,并且您的前端可以查看告诉用户进度,然后在完成后显示结果。

答案 3 :(得分:2)

如果您确实想要完全关闭应用程序,我建议您在SQL Server代理中定义一个作业,并只执行一个T-SQL语句来手动启动该作业。语法是:

sp_start_job 
     {   [@job_name =] 'job_name'
       | [@job_id =] job_id }
     [ , [@error_flag =] error_flag]
     [ , [@server_name =] 'server_name']
     [ , [@step_name =] 'step_name']
     [ , [@output_flag =] output_flag]

作业将执行您的存储过程。你必须要有点创意才能传递任何论点。例如,将参数插入“队列”表并让作业处理队列中的所有行。

队列中的插入触发器也应该起作用,而不是作业。

答案 4 :(得分:2)

我更喜欢使用后台服务进行离线处理,用户应用程序告诉服务该做什么,然后断开连接。该服务可以记录已用时间和错误/状态,并在必要时重新启动。 WCF专为此而设计,并支持与之通信的队列。

答案 5 :(得分:1)

  

让他们关闭应用程序然后来   稍后回来

如果您要允许他们完全关闭应用程序,则必须在不同的ThreadPool中启动单独的.exe或其他东西来执行调用存储过程的代码。否则,当您关闭应用程序时,您的线程将会死亡。

答案 6 :(得分:1)

您可以做的另一种方法是允许您的应用程序在后台运行(可能在通知区域中),然后在作业完成时退出或通知。您可以使用BeginExecuteNonQuery和EndExecuteNonQuery方法来允许它在单独的线程中运行。

答案 7 :(得分:0)

您的应用程序的主窗口不需要打开。如果您将其作为辅助线程启动,它将继续运行IsBackground == false。我通常喜欢通过SQL Server代理或作为客户端 - 服务器应用程序来做这些事情(没有什么能阻止客户端 - 服务器应用程序在同一台机器上运行,甚至是同一个二进制文件)。

已经有一段时间......

using System.Threading;

.....

Thread _t = null;
void StartProcedure()
{
  _t = new Thread(new ThreadStart(this.StartProc));
  _t.IsBackground = false;//If I remember correctly, this is the default value. 
  _t.Start();
}

bool ProcedureIsRunning
{
 get { return _t.IsRunning; } //Maybe it's IsActive. Can't remember. 
}

void StartProc(object param)
{
  //your logic here.. could also do this as an anonymous method. Broke it out to keep it simple. 
}