2009-08-04 7 views
16

Ich rufe eine gespeicherte Prozedur von meiner Anwendung, die 30 Minuten dauern kann, um auszuführen.Führen Sie eine gespeicherte Prozedur asynchron aus einem Windows-Formular aus, und trennen Sie dann die Verbindung?

Ich möchte nicht meinen Benutzer die Anwendung für den gesamten Zeitraum geöffnet lassen. Also möchte ich den Sproc anrufen, lass ihn fliegen und lass ihn die Anwendung herunterfahren und später wiederkommen.

Wie kann ich das tun?

+0

Nun, ich werde mich nicht anmelden oder registrieren (irgendwie enttäuscht, dass ich nicht wählen oder schließen kann, ohne das zu tun). Wie auch immer, Scott W. gab die beste Antwort und wurde dann von einigen unterstützenden Stellen unterstützt. Alle akzeptieren das Bit "... schneller Hardware kaufen". Ich würde nur behaupten, Fehler zu scheitern, als meinen Kunden sagen, sie müssen schneller Hardware kaufen, weil ich es nicht richtig machen kann. Danke für deine Hilfe! –

+2

@Dan - Ich bin verwirrt. Sie sind bereits eingeloggt, mindestens genug, um ein Benutzerkonto und 2 Badges zu haben. Warum können Sie nicht auf die Schaltfläche "Antwort annehmen" klicken? –

+0

Siehe auch ... http://stackoverflow.com/questions/7444215/how-to-execute-a-sql-server-stored-procedure-asynchron-and-ensure-its-comp – SteveC

Antwort

1

ließ sie die App herunterfahren und kommen später zurück

Wenn Sie sie vollständig schließen die App ermöglichen gehen, werden Sie eine separate exe starten müssen oder etwas in einem anderen ThreadPool, das den Code ausführt, der die gespeicherte Prozedur aufruft. Andernfalls stirbt dein Thread, wenn du die App schließt.

+0

Ich stimme zu, wenn Sie möchten Damit Ihre Anwendung geschlossen werden kann, müssen Sie den Sproc-Aufruf vollständig aus dem ursprünglichen Prozess entfernen. – Joshua

3

können Sie die BeginExecuteXXX/EndExecuteXXX Methoden verwenden (je nachdem, ob es ein Ergebnis oder nicht zurückgibt) des SqlCommand, einen Delegierten Rückruf übergeben.

+0

Ich weiß nicht, warum Leute abstimmen, ohne zu erklären warum. Dies ist eine absolut gültige Antwort, wenn Sie den Vorgang ausführen möchten, ohne das Programm vollständig herunterzufahren. – Joshua

+0

Ich kann den Grund erraten: Der Thread-Thread für BeginXXX wird abgebrochen, wenn der Haupt-Thread existiert. Ich ging jedoch davon aus, dass das OP die App im Hintergrund offen halten möchte, anstatt den Prozess vollständig abzuschalten (was ich für eine gültige Annahme halte). –

+0

Ich wollte nicht abstimmen, wenn ich das tue (neu dazu) Forum, also habe ich vielleicht auf Unfall geklickt und nicht realisiert, was ich tat). Ich stimme zu, vollkommen gute Lösung ... aber ach, ich möchte sie die App komplett umbringen lassen. Thx Mehrdad. –

2

Ich schlage eine Re-Architektur vor. Erstellen Sie eine Tabelle "Arbeitswarteschlange", in der Sie Anforderungen protokollieren, um die gespeicherte Prozedur auszuführen. Dann haben Sie entweder einen Windows-Dienst oder einen SQL-Server-Job, der diese Arbeitswarteschlange von Zeit zu Zeit überprüft (oder wirklich genial ist und einen Trigger verwendet), um die gespeicherte Prozedur zu starten. Lassen Sie die gespeicherte Prozedur den Fortschritt von Zeit zu Zeit in der Arbeitswarteschlangentabelle aktualisieren, und Ihr Front-End kann den Fortschritt anzeigen und die Ergebnisse anzeigen, wenn sie fertig sind.

+0

Nun, ich werde mich nicht einloggen oder registrieren (irgendwie enttäuscht, dass ich nicht abstimmen kann, ohne das zu tun). Wie auch immer, das war die beste Antwort für mich und wurde dann von einigen unterstützenden Posts unterstützt. Alle akzeptieren das Bit "... schneller Hardware kaufen". Ich würde nur behaupten, Fehler zu scheitern, als meinen Kunden sagen, sie müssen schneller Hardware kaufen, weil ich es nicht richtig machen kann. Vielen Dank für Ihre Hilfe! –

+0

@Dan - die "schnellere Hardware kaufen" war nur ein Scherz. Ich werde es bearbeiten, um es zu entfernen. Aber schnellere Hardware ist manchmal eine Option. Sie werden jedoch keine Hardware finden, die 30 mal schneller ist! ;) –

+1

@Scot, du beschreibst im Grunde ein eingebautes Feature: Service Broker Aktivierung.Sowohl die interne als auch die externe Aktivierung ist wohl besser als ein Windows-Dienst oder ein Agent-Job, der von Zeit zu Zeit überprüft. –

1

Eine andere Methode, die Sie ausführen können, besteht darin, Ihre Anwendung im Hintergrund ausführen zu lassen (möglicherweise im Benachrichtigungsbereich) und dann zu beenden oder zu benachrichtigen, wenn der Job abgeschlossen ist. Sie können dies verwenden, indem Sie die Methoden BeginExecuteNonQuery und EndExecuteNonQuery verwenden, um die Ausführung in einem separaten Thread zu ermöglichen.

2

Wenn Sie Ihre Anwendung wirklich vollständig schließen möchten, empfehle ich, einen Auftrag im SQL Server-Agent zu definieren und eine T-SQL-Anweisung auszuführen, um diesen Auftrag manuell zu starten. Die Syntax lautet:

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] 

Der Job würde Ihre gespeicherte Prozedur ausführen. Sie müssen ein wenig kreativ sein, um irgendwelche Argumente zu übergeben. Fügen Sie beispielsweise die Parameter in eine "Queue" -Tabelle ein und lassen Sie den Job alle Zeilen in der Warteschlange verarbeiten.

Anstelle eines Jobs sollte ein Insert-Trigger in Ihrer Warteschlange ebenfalls funktionieren.

0

Das Hauptfenster Ihrer Anwendung muss nicht geöffnet sein. Wenn Sie es als sekundären Thread gestartet haben, wird es weiterhin so lange ausgeführt, wie IsBackground == false. Gewöhnlich bevorzuge ich dies über den SQL Server-Agenten oder als Client-Server-Anwendung (nichts hindert eine Client-Server-App daran, auf demselben Computer ausgeführt zu werden oder sogar dieselbe Binärdatei zu verwenden).

Es ist eine Weile her ...

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. 
} 
2

Ich ziehe einen Hintergrunddienst für die Offline-Verarbeitung zu verwenden, wo Ihre Benutzer App den Dienst sagt, was zu tun und dann trennt. Der Dienst kann abgelaufene Zeiten und Fehler/Status protokollieren und bei Bedarf neu starten. WCF ist dafür ausgelegt und unterstützt die Kommunikation mit Warteschlangen.

+2

Remus hatte eine gute Antwort, und ich schätze es, dass er sich die Zeit genommen hat, den Blogartikel zu posten. Das wäre viel weniger Arbeit als das Erstellen eines separaten Hintergrunddienstes, wenn es für Ihr Problem geeignet ist. –

24

Dies ist eigentlich ein ziemlich häufiges Szenario.Sie können nichts auf der Client-Basis tun, da der Client weggehen und sich trennen kann und Sie die bisher erreichte Arbeit verlieren. Die Lösung besteht darin, Service Broker Activation zu verwenden: Sie erstellen einen Dienst in der Datenbank und fügen eine aktivierte Prozedur hinzu. In Ihrer Anwendung (oder ASP-Seite) senden Sie eine Nachricht an den Dienst und betten die notwendigen Parameter für Ihre Prozedur ein. Nachdem Ihre Anwendung festgeschrieben wurde, aktiviert die Nachricht die Dienstprozedur. Die Dienstprozedur liest die Parameter aus der Nachricht und ruft Ihre Prozedur auf. Da die Aktivierung auf einem Server-Thread stattfindet, der nicht mit Ihrer ursprünglichen Verbindung zusammenhängt, ist dies zuverlässig. Tatsächlich kann der Server sogar herunterfahren und neu starten, während Ihre Prozedur ausgeführt wird und die Arbeit wird zurückgerollt, dann fortgesetzt, da die aktivierende Nachricht die Dienstprozedur nach dem Neustart erneut auslösen wird.

aktualisiert

ich die Details, wie veröffentlicht habe diesen einschließlich Beispielcode auf meinem Blog zu tun: Asynchronous procedure execution.

+2

Ausgezeichnete Details im Blog! –

+2

Ja! Vielen Dank. Eine Sache, um sicherzustellen: Der Service Broker muss für die Datenbank aktiviert werden. (Datenbankeigenschaften -> Optionen in SSMS) oder ALTER DATABASE ... SET ENABLE_BROKER. Das Schöne daran ist, dass dies sogar in Express Editions von SQL Server funktioniert! – tony722

+0

@Remus Rusanu, ich habe den Code aus Ihrem Artikel (scheint Kommentare sind deaktiviert dort) und stieß auf ein seltsames Verhalten. Wenn ich ein gespeichertes Proc schreibe, um INST in eine Tabelle in meiner db einzufügen und dann WAITFOR einige, dann führe es durch die ups_AsyncExecInvoke, bekomme ich meine ganze Tabelle blockiert, während der Proc ausgeführt wird (z. B. kann ich SELECT nicht mehr für diese Tabelle tun); Wenn ich den gleichen Prozess direkt (ohne die Broker-Nachricht) ausführen, blockiert die Tabelle nicht. Irgendwelche Ideen? – zaitsman

Verwandte Themen