Ich möchte Folgendes erreichen:
Innerhalb einer Transaktion möchte ich mehrere Protokollnachrichten generieren. Diese Protokollmeldungen sollten nur geschrieben werden, wenn die Transaktion erfolgreich übergeben wurde. Wenn die Transaktion zurückgesetzt wird, dürfen die Protokollnachrichten nicht protokolliert werden.
Ich konnte nichts finden, um dies zu erreichen (mit Frühling, Winterschlaf, Atomikos), also schrieb ich diesen kleinen Wrapper (ich habe ein paar Convenience-Methoden weggelassen):
%Vor%Was halten Sie von diesem Ansatz? Gibt es größere oder kleinere Fehler oder Probleme damit? Oder noch besser, gibt es dafür fertige Lösungen?
UPDATE:
Da ich auch JTA verwende, habe ich eine neue Idee. Würde die Implementierung des TransactionLoggers als Empfänger einer transaktionsbewussten Nachrichtenwarteschlange das Zeitproblem lösen oder würde es die Dinge nur noch komplexer machen?
UPDATE:
Ich denke, dass die Protokollierung in einer Datenbank und das periodische Schreiben von Protokolleinträgen aus dieser Datenbank in eine periodische Aufgabe, wie in den Kommentaren vorgeschlagen, eine sehr gute Lösung für dieses Problem ist:
PROs:
CONs:
Hier sind die Vor- und Nachteile, die ich mit dem Wrapper sehe, den ich gepostet habe:
PROs:
CONs:
rollback()
und commit()
müssen "manuell" aufgerufen werden, was zu Programmierfehlern führen kann (und möglichem OutOfMemoryError, wenn das Aufrufen dieser Methoden vergessen wird) Ich denke, eine Kombination dieser beiden, wie das Protokollieren von Protokollsätzen im "Wrapper" -Ansatz, ist wegen der möglichen inkonsistenten Protokolldateien (vergessene Protokolleinträge aufgrund eines Anwendungsabsturzes) schlechter als die Verwendung eines der beiden erwähnten Ansätze. .
Meine Entscheidung ist jetzt, meinen "Wrapper" zu behalten. Die folgenden Gründe sind für diese Entscheidung entscheidend (in der Reihenfolge ihrer Wichtigkeit):
rollback()
und commit()
auf nur wenige Methoden reduzieren. Übrigens: Ich möchte mein Englisch verbessern. Also, wenn Sie irgendwelche Fehler in meinem Artikel bemerken, werde ich mich freuen, wenn Sie sie aufzeigen.
UPDATE:
Einfach ausgedrückt benutze ich es so:
%Vor%Das ist immer noch nicht perfekt, aber im Moment scheint es mir eine "gute Lösung" zu sein. Der nächste Schritt wird Aspekte verwenden, um meine Transaktions-Methoden zu dekorieren.
UPDATE:
Ich füge das in meine Frage ein, weil ich mich schlecht fühlte, meine eigene Antwort zu akzeptieren, obwohl jemand anderes mich auf den Weg gebracht hat.
Ich verwende jetzt einen AOP-Ansatz im Wesentlichen mit dem folgenden Logger. (In meiner realen Anwendung habe ich mehr als einen Logger und alle diese Logger werden von einem benutzerdefinierten Singleton-Manager verwaltet.):
%Vor%und dieser Aspekt:
%Vor%In meiner applicationContext.xml habe ich die folgenden Zeilen:
%Vor%Das funktioniert bis jetzt gut.
PROs:
rollback()
und commit()
werden automatisch nach jeder Transaktion CONs:
Warum erstellen Sie nicht einen Aspekt und implementieren einen Rat, vor allem einen Nach der Rückmeldung, überprüfen Sie die Dokumentation des Frühlings, die seit 2.0 verfügbar ist:
%Vor%Wenn Sie nur anmelden müssen, wenn alles in Ordnung ist, erstellen Sie den Hinweis und lassen Sie Ihren Code sauber:
%Vor% Wenn Sie möchten, dass ein Logger seine Log-Nachrichten nur dann "festschreibt", wenn die Transaktion festgeschrieben ist, dann wäre Ihre beste Lösung, wenn Ihr Logger ein XAResource
wäre und XA-Transaktionen verwendet. Das bedeutet, dass Ihr XALogger vom Transaktionsmanager eine Prepare / Commit-Benachrichtigung erhält. Auf diese Weise wird Ihre XAResource zu einem "Resource Manager", der an einer XA-Transaktion teilnimmt. Ihr XALogger muss genau wie JMS- und JDBC-Ressourcen beim Transaktionsmanager registriert sein.
Sie können entweder eine JCA-Implementierung schreiben oder (einfacher) Ihren XALogger mit dem aktuellen java.transaction.Transaction
transaction.enlistResource(myXALogger)
und implementieren Sie XAResource
(JavaDoc)
Es ist nicht klar, was du mit der rec.setMillis(System.currentTimeMillis());
erreichen willst.
Das protokollierte Ereignis trat zum Zeitpunkt der Datensatzerstellung und nicht zum Zeitpunkt der Festschreibung auf. Es wird nur bis zur Commit-Zeit im RAM gepuffert. Indem Sie es auf diese Weise überschreiben, protokollieren Sie die Commit-Zeit und nicht die Ereignisauftrittszeit. Beim Lesen des Protokolls müssen Sie einen Hinweis auf die tatsächliche Reihenfolge haben, oder Sie werden nicht in der Lage sein, kausale Beziehungen zu interpretieren.
Ihre Lösung leidet auch unter Problemen bei der Wiederherstellung nach einem Absturz. Der Transaktionsmanager verarbeitet das Commit für Transaktionsressourcen, die volatilen Protokollnachrichten gehen jedoch verloren. Das kann oder kann nicht tolerierbar sein, abhängig von Ihren Anforderungen.
Also, ich möchte abholen, wo die Kommentare Sie verlassen haben :) @MichaelBorgwardt schlägt vor, zu einer Datenbank zu loggen und @cherouvim fügte hinzu, dass Sie die Protokolleinträge regelmäßig aus der Datenbank in die Datei schreiben sollten.
Es ist auch möglich, die Umwandlung der Protokolleinträge in die Datei direkt nach dem Festschreiben der Transaktion durch einen bestimmten Thread zu starten (auf diese Weise wird die Lücke zwischen dem Commit und dem Haben in der Datei vermieden).
Eine andere Möglichkeit wäre, eine Protokolldatei für jede Transaktion zu schreiben. Beim 'Rollback' löschen Sie es. Bei 'commit' hängen Sie es an Ihre bereits existierende Logdatei an (oder Sie entscheiden sich sowieso, keine Logdatei zu haben, sondern ein logdir und bei 'commit' verschieben Sie die einzelne Logdatei).
Es gibt einen Abschnitt zum Thema Protokollierung in der Frühlingsreferenz.
Es zeigt, wie man verschiedene Logging-Frameworks konfiguriert, darunter log4j
In Ihrem Fall wäre die letzte Zeile der Konfiguration:
%Vor%Tags und Links java spring logging transactions