我正在从我的应用程序调用存储过程,可能需要30分钟才能执行。
我不想让我的用户在整个时间段内打开应用程序。所以我想调用sproc,让它飞起来,让他们关闭应用程序并稍后再回来。
我该怎么做?
答案 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.
}