2017-04-30 2 views
0

Sie müssen Daten in die Datenbank einfügen, die mehrere Threads verwenden, aber auch wenn ein einzelner Thread nicht festgeschrieben werden kann, muss die gesamte Transaktion zurückgesetzt werden.Transaktion in Multithread-Umgebung verarbeiten

Freigeben von Verbindungsobjekt zwischen Thread und join() verwenden, um zu warten, bis untergeordneter Thread beendet wird, aber dies sieht wie schlechtes Design aus, da ich Verbindungsobjekt unter Threads teile.

Kann jemand besseres Design vorschlagen, um das zu lösen (nicht sicher, sollte ich für verteilten txn Manager oder nicht gehen)?

+0

Verwenden Sie CountDownLatch im übergeordneten Thread https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html. Verwenden Sie auch savePoint und Rollback, um den Rollback zu steuern und den Transaktionsfortschritt zu überwachen. Https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html – Saurabh

+0

savePoint und rollback funktionieren auf Verbindungsebene, und wenn ich sie verwende Mehrfachverbindung, dies wird nur das bestimmte txn zurückrollen, nicht alle txn, die gerade in anderen Threads ausgeführt werden. – RE350

+0

Ich sehe, dann erfordert es die Verwendung einiger Transaktionsmanager. JBoss stellt einen zur Verfügung, wenn Sie diesen als App-Server verwenden, bindet dann aber Ihre Anwendung an JBoss. Ich erinnere mich nicht richtig daran, aber Spring hatte auch ein TM-Angebot. – Saurabh

Antwort

2

Ich würde vorschlagen, alle SQL-Aktionen aus mehreren Threads in einer Zwischendatenstruktur in die Warteschlange zu stellen, und dann in der Datenbank aus einem einzigen Thread. Es ist möglich, die fadensicheren Zwischenstrukturen wie ConcurrentHashMap, ConcurrentLinkedQueue zu haben, oder Sie können einfach nur synchronisieren, wenn Sie damit arbeiten.

Auf diese Weise müssen Sie die Transaktion nicht im Voraus starten. Die ausstehenden Daten sind möglicherweise weniger sicher, aber ich nehme an, dass sie in der Datenbank nicht viel sicherer sind, während die Transaktion noch nicht festgeschrieben ist.

Dies kann natürlich nur funktionieren, wenn Sie keine select Anweisungen haben, die nicht festgeschriebene Transaktionsdaten aus derselben Transaktion abrufen. Um solche Anfragen auf die eine oder andere Weise loszuwerden, ist möglicherweise ein Redesign erforderlich.

Verwenden Sie CountDownLatch, um zu erkennen, wenn alle Daten bereit sind und der Datenbank-Schreib-Thread seine Aktion starten soll. Wenn dies nie der Fall ist, verwenden Sie das Reaktormuster für den Datenbank-Schreib-Thread.

1

Hier sind meine schnellen Gedanken mit möglichen Umsetzungsschritten:

  • Ihre Eltern Verarbeitungs-Thread wird (1.) neue Themen erstellen parallel DB Einsätze zu tun, (2.) erstellen CountDownLatch Objekt (Dadurch wird der übergeordnete Thread beibehalten, bis alle untergeordneten Threads, die DB-Einfügungen ausführen, beendet sind.) (3.) Erstellen Sie ein Db-Verbindungsobjekt mit Auto-Commit-Modus als FALSE.
    • Angenommen, Sie 6 Threads laichen dann zu tun parallel DB fügt Sie CountDownLatch Objekt wie dieses CountDownLatch countDownLatch = new CountDownLatch(6) schaffen und dann parallel Threads erzeugen und countDownLatch.await()
  • Ihre parallele Threads tun Einfügen in DB starten, aber Schlüssel Sache ist, dass jeder von ihnen db Verbindungsobjekt im Auto-Commit-FALSE-Modus, der von übergeordneten Thread zur Verfügung gestellt wurde, so im Grunde kein Kind-Thread wird die Db-Commit.
  • Sobald jeder untergeordnete Thread fertig ist, werden sie countDownLatch.countDown(); tun, um den Latch-Zähler zu dekrementieren.
  • Bitte beachten Sie, dass Sie die countDownLatch sowie db Verbindungsobjekt zu jedem Thread zur Verfügung stellen müssen, ich bin sicher, dass Sie wissen würden, wie.
  • Sobald Latch Zähler 0 erreicht, Ihre Mutter Thread-Ausführung wieder beginnen wird (bis Latch-Zähler nicht 0 ist, wird countDownLatch.await() den Faden halten) und dann (1.) können Sie entscheiden, ob basierend zu begehen oder nicht auf Ergebnis von jedem Thread (2.) Schließen Sie das Verbindungsobjekt.Jetzt, Runnable gibt nichts zurück, so besser nutzen Callable, so dass jeder Thread über ihren Status informieren kann.
  • Wenn Sie Spring verwenden, kann es Ihre Arbeit mit seiner Transaktionsfunktion erleichtern, aber das wird eine andere Geschichte.


    nun einige Punkte zu wissen, was Sie in Ihrer Frage erwähnt - Sie erwähnten „selbst wenn ein einzelner Thread zu begehen ausfällt, müssen alle Transaktions Rollback“, im Grunde, wenn alle Ihre db insert/Zugriff schlägt dann fehl Sie wollen nichts begehen, also wird Ihre Callable den Status ihrer Ausführung zurückgeben, ich bin nicht sicher, was Sie sonst noch damit meinen könnten, aber ich denke, wenn Sie den Punkt über Callable haben, dann sollten Sie in Ordnung sein. Außerdem erwähnten Sie ", aber das sieht wie schlechtes Design aus, da ich das Verbindungsobjekt unter Threads teile.", müssen Sie das Db-Verbindungsobjekt freigeben, weil, sobald eine Transaktion festgeschrieben ist, Sie kein Rollback durchführen können, also wollen Sie nicht Um das Verbindungsobjekt zu teilen, müssen Sie wahrscheinlich eine SQL-Anweisung haben, um die Arbeit, die durch den früheren Datenbankzugriff und ihre Commits erledigt wurde, rückgängig zu machen.

    Verwandte Themen