Verwalten von Threads, die mit Java auf eine Datenbank zugreifen

9

Ich arbeite an einer App, die auf eine SQLite-Datenbank zugreift. Das Problem ist, dass die DB gesperrt wird, wenn eine Anfrage an sie vorliegt. Meistens ist das kein Problem, weil der Fluss der App ziemlich linear ist.

Allerdings habe ich einen sehr langen Berechnungsvorgang, der vom Benutzer ausgelöst wird. Dieser Prozess umfasst mehrere Aufrufe an die Datenbank zwischen Berechnungen.

Ich wollte, dass der Benutzer ein visuelles Feedback erhält, also habe ich den javafx progress indicator und einen Service aus dem Framework Javafx.Concurrency verwendet. Das Problem besteht darin, dass der Benutzer sich frei in der App bewegen und möglicherweise andere Aufrufe an die Datenbank auslösen kann.

Dies verursachte eine Ausnahme, dass die Datenbankdatei gesperrt ist. Ich möchte einen Weg finden, diesen Thread zu stoppen, wenn dieser Fall auftritt, aber ich konnte keine klaren Beispiele online finden. Die meisten von ihnen sind zu stark vereinfacht und ich möchte einen Weg, der skalierbar ist. Ich habe versucht, die Methode cancel () zu verwenden, aber das garantiert nicht, dass der Thread rechtzeitig abgebrochen wird.

Da ich nicht in der Lage bin, alle Teile des Codes für isCancelled einzuchecken, gibt es manchmal eine Verzögerung zwischen dem Zeitpunkt, an dem der Thread abgebrochen wird, und der Zeit, zu der er effektiv gestoppt wird.

Also dachte ich über die folgende Lösung nach, aber ich würde gerne wissen, ob es einen besseren Weg in Bezug auf Effizienz und Vermeidung von Rennbedingungen und Hängen gibt.

%Vor%

Dies ist meine Serviceklasse, die ich unterklassifiziert habe, um Methoden einzuschließen, die verwendet werden können, um den Status des Dienstes (gestoppt oder nicht gestoppt) festzulegen

%Vor%

Der Dienst implementiert diese Schnittstelle, die ich definiert habe

%Vor%

Alle Dienste müssen sich beim Thread-Manager registrieren, der eine Singleton-Klasse ist.

%Vor%

An jeder Stelle in der App, wenn wir den Dienst stoppen wollen, rufen wir cancelServices () auf. Dadurch wird der Status auf abgebrochen gesetzt. Ich überprüfe dies in meinem calculationMethod () und setze den Status auf kurz vor dem Zurücksetzen (um den Thread zu beenden).

%Vor%     
user3552551 30.08.2017, 21:28
quelle

4 Antworten

3

(Ich gehe davon aus, dass Sie JDBC für Ihre Datenbankabfragen verwenden und dass Sie die Kontrolle über den Code haben, der die Abfragen ausführt)

Ich würde alle Datenbankzugriffe in einer Singleton-Klasse zentralisieren, wodurch der letzte PreparedStatement die aktuelle Abfrage in einem einzigen Thread ausführen würde. ExecutorService . Sie könnten dann diese Singleton-Instanz wie isQueryRunning() , runQuery() , cancelQuery() fragen, die synchronized wäre, so dass Sie entscheiden können, dem Benutzer eine Nachricht anzuzeigen, wann immer die Berechnung abgebrochen werden sollte, abbrechen und eine neue starten eins.

Etwas wie (fügen Sie Null-Checks und catch (SQLException e) Blöcke hinzu):

%Vor%     
Matthieu 08.09.2017 20:21
quelle
0

Eine Lösung für Ihr Problem könnte Thead.stop() sein, was vor Jahrhunderten veraltet war (mehr zum Thema hier ).

Um das ähnliche Verhalten zu implementieren, wird empfohlen, das Thread.interrupt() zu verwenden, was (im Kontext von Task ) dasselbe ist wie das Task.cancel() .

Lösungen:

  • Füllen Sie Ihre calculationMethod mit isCancelled() checks.
  • Versuchen Sie, eine Unterstreichungsoperation durch eine andere Thread zu unterbrechen.

Die zweite Lösung ist wahrscheinlich, was Sie suchen, aber es hängt vom tatsächlichen Code von calculationMethod ab (was ich denke, dass Sie nicht teilen können).

Generische Beispiele zum Beenden langer Datenbankoperationen (all dies wird von einem anderen Thread ausgeführt):

  • Beenden Sie die Verbindung zur Datenbank (vorausgesetzt, die Datenbank ist intelligent genug, um den Vorgang beim Trennen der Verbindung zu beenden und anschließend die Datenbank zu entsperren).
  • Bitten Sie die Datenbank, eine Operation zu beenden (zB kill <SPID> ).

BEARBEITEN:

Ich habe nicht gesehen, dass Sie die Datenbank für SQLite angegeben haben, als ich meine Antwort geschrieben habe. Also, um die Lösungen für SQLite anzugeben:

  • Das Beenden der Verbindung wird nicht helfen
  • Suchen Sie nach dem Äquivalent von sqlite3_interrupt in Ihrer Java-SQLite-Schnittstelle
MaanooAk 05.09.2017 13:43
quelle
0

Vielleicht können Sie Thread-Instanz t1, t1.interrupt () Methode aufrufen, dann in der run-Methode von thread (Vielleicht calculationMethod), fügen Sie eine bedingte Anweisung.

%Vor%     
Jacky 08.09.2017 21:39
quelle
0

Mit dem WAL-Modus (Write-ahead-Protokollierung) können Sie viele Abfragen parallel zur SQLite-Datenbank durchführen

  

WAL bietet mehr Parallelität, da Leser keine Writer blockieren und a   Der Autor blockiert die Leser nicht. Lesen und Schreiben kann weitergehen   gleichzeitig.

Ссылка

Vielleicht sind diese Links für Sie interessant:

Ссылка Ссылка Ссылка

    
user60108 09.09.2017 04:02
quelle

Tags und Links