Wir haben eine Java-Workflow-Anwendung, die eine Oracle-Datenbank verwendet, um ihre Schritte und Interaktionen mit anderen Diensten zu verfolgen. Während eines Arbeitsablaufs werden mehrere Einfüge- / Aktualisierungs- / Auswahlvorgänge ausgeführt, und gelegentlich gibt die Auswahl die aktualisierten Daten nicht zurück, obwohl das Einfüge- / Aktualisierungsfestschreiben, das vor dem erfolgreichen Abschluss ausgeführt wurde, ausgeführt wurde. Nachdem die Arbeitsablauffehler (aufgrund der schlechten Daten) behoben sind, werden die neuen / aktualisierten Daten angezeigt, wenn wir zurückgehen und die Datenbank über eine Drittanbieter-App überprüfen. Es scheint eine Verzögerung zu geben zwischen dem Zeitpunkt, zu dem unsere Commits durchlaufen werden und wenn sie sichtbar sind. Dies geschieht in etwa 2% aller Workflow-Läufe und steigt bei starker Datenbanknutzung.
Unser Datenbank-Support-Team schlug vor, einen Parameter max-commit-propagation-delay auf 0 zu ändern, da dieser standardmäßig auf 700 gesetzt wurde. Dies schien eine mögliche Lösung zu sein, behob jedoch unser Problem nicht.
Die Anwendung wird auf WebSphere ausgeführt, und die Oracle-Datenbank ist als JDBC-Datenquelle konfiguriert. Wir verwenden Oracle 10.1g. Die Anwendung ist in Java 1.5 geschrieben.
Jede Hilfe wäre willkommen.
edit: Beispielcode
%Vor%Das von Ihnen beschriebene Verhalten sollte standardmäßig nicht möglich sein. Änderungen, die in einer festgeschriebenen Transaktion vorgenommen werden, sind sofort für alle Sitzungen verfügbar. Es gibt jedoch Ausnahmen:
Verwenden Sie eine der WRITE-Optionen im COMMIT-Befehl? Wenn dies nicht der Fall ist, bestätigen Sie den Wert Ihres Initialisierungsparameters COMMIT_WRITE. Wenn entweder "WRITE BATCH" oder speziell "WRITE BATCH NOWAIT" verwendet wird, könnten Sie sich für Nebenläufigkeitsprobleme öffnen. "WRITE BATCH NOWAIT" wird normalerweise in Fällen verwendet, in denen die Geschwindigkeit Ihrer Schreibtransaktionen wichtiger ist als mögliche Nebenläufigkeitsprobleme. Wenn Ihr Initialisierungsparameter die "WRITE" -Varianten verwendet, können Sie sie auf Transaktionsbasis überschreiben, indem Sie die IMMEDIATE-Klausel in Ihren Commits angeben ( siehe COMMIT )
Ist die Transaktion, die versucht, die Daten zu lesen, die SET TRANSACTION aufrufen, bevor die andere Transaktion festgeschrieben wird? Die Verwendung von SET TRANSACTION zur Angabe von SERIALIZATION LEVEL READ ONLY oder SERIALIZABLE führt dazu, dass die Transaktion keine Änderungen erkennt, die von anderen festgeschriebenen Sitzungen nach dem Aufruf von SET TRANSACTION auftreten ( siehe SET TRANSACTION )
edit: Ich sehe, dass Sie eine DataSource-Klasse verwenden. Ich bin nicht vertraut mit dieser Klasse - ich nehme an, es ist eine Verbindung, die Ressource teilt. Ich weiß, dass Ihr aktuelles App-Design es nicht einfach macht, dasselbe Verbindungsobjekt in Ihrem gesamten Arbeitsablauf zu verwenden (die Schritte können unabhängig voneinander ausgeführt werden, und Sie haben keine Möglichkeit eingebaut, ein Verbindungsobjekt von einem Schritt an den zu übergeben Als nächstes sollten Sie überprüfen, ob Verbindungsobjekte, die an das DataSource-Objekt zurückgegeben werden, "sauber" sind, insbesondere im Hinblick auf offene Transaktionen. Es kann sein, dass Sie SET TRANSACTION in Ihrem Code nicht aufrufen, aber ein anderer Consumer von DataSource dies möglicherweise tut und die Verbindung zurück zur Datenquelle mit der Sitzung im SERIALIZABLE- oder READ ONLY-Modus zurückgibt. Bei der Verbindungsfreigabe müssen alle Verbindungen zurückgesetzt werden, bevor sie an einen neuen Kunden übergeben werden.
Wenn Sie das Verhalten der DataSource-Klasse nicht kontrollieren oder nicht sehen können, möchten Sie möglicherweise einen ROLLBACK für die neu erworbene Verbindung ausführen, um sicherzustellen, dass keine veraltete Transaktion bereits eingerichtet ist.
Wenn das DBA-Team versucht hat, den Parameter max_commit_propagation_delay
zu ändern, bedeutet dies wahrscheinlich, dass Sie eine Verbindung zu einer RAC-Instanz herstellen (i-e: mehrere unterschiedliche Server, die auf eine einzelne Datenbank zugreifen).
Wenn Sie in diesem Fall die Verbindung in Ihrem Java-Code schließen und erneut öffnen, besteht die Möglichkeit, dass Sie von einem anderen Server beantwortet werden. Der Verzögerungsparameter bedeutet, dass es einen kleinen Zeitrahmen gibt, wenn die beiden Instanzen nicht genau zum selben Zeitpunkt sind. Die Antwort, die Sie erhalten, ist konsistent mit einem Zeitpunkt, aber möglicherweise nicht der aktuellste.
Wie von KM vorgeschlagen, wäre die einfachste Lösung, die Verbindung nach dem Festschreiben geöffnet zu lassen.
Alternativ können Sie nach dem Schließen der Verbindung auch eine Verzögerung hinzufügen, wenn dies praktisch ist (wenn es sich um einen Stapeljob handelt und die Antwortzeit beispielsweise nicht kritisch ist).
Das klingt wie ein Problem mit RAC, mit Verbindungen zu zwei verschiedenen Instanzen und der SCN ist nicht synchron.
Um dies zu vermeiden, ziehen Sie in Betracht, die Datenbankverbindung nicht zu schließen und eine neue Verbindung zu erhalten, sondern dieselbe Verbindung wiederzuverwenden.
Wenn das nicht funktioniert, fügen Sie der Abfrage, die versucht, die eingefügte Zeile abzurufen, einen Wiederholungsversuch hinzu. Wenn die Zeile nicht zurückgegeben wird, schlafen Sie ein wenig und wiederholen Sie die Abfrage erneut. Setzen Sie das in eine Schleife, nach einer bestimmten Anzahl von Wiederholungen können Sie dann fehlschlagen.
[ANHANG]
In seiner Antwort wirft Steve Broberg (+1!) interessante Ideen auf. Ich hatte nicht bedacht:
COMMIT
könnte etwas anderes als IMMEDIATE WAIT
sein
Ich habe die Möglichkeit einer Flashback-Abfrage in Betracht gezogen und diese ohne weiteres ausgelassen, da es keinen ersichtlichen Grund dafür gibt, dass das OP eine Flashback-Abfrage verwendet und im Code-Snippet kein Beweis dafür vorliegt. p>
[/ ANHANG]
Das Code-Snippet enthielt das Commit nicht wirklich.
Wenn Sie davon ausgehen / sich auf die enge Verbindung verlassen, die das Commit ausführt, ist es möglicherweise nicht synchron (dh das Java kann die Verbindung als geschlossen melden, wenn es Oracle anweist, die Verbindung zu schließen, was bedeutet, dass es möglicherweise vor dem Commit liegt wird von Oracle abgeschlossen).
Ich sehe keinen Commit in Ihrem Code. Sie sind die wichtigsten Aussagen in einer solchen App, so dass ich sie jedes Mal explizit geschrieben haben möchte, ohne sich auf close () oder ähnliches zu verlassen.
Sie können auch autocommit standardmäßig auf Ihre Verbindung (en) setzen, was das Verhalten genau erklärt (es wird nach jedem Einfügen / Update bestätigt).
Können Sie überprüfen, ob Sie genau an dem Punkt, an dem Sie sie haben möchten, festgelegt haben, z. am Ende der Transaktion und nicht vorher?
Wenn es Commits gibt, wenn Sie teilweise durch sind, dann haben Sie eine Race-Bedingung zwischen Ihren Threads, die auch erklären würde, warum es mehr Probleme gibt, wenn die Last größer ist.
", obwohl das insert / update-Commit vor dem erfolgreichen Abschluss ausgeführt wurde."
Dies deutet darauf hin, dass Sie ein commit () ausgeben und danach erwarten, dass Sie genau dieselben Daten erneut lesen (das ist wiederholbares Lesen).
Dies deutet darauf hin, dass Sie nicht begehen sollten. Solange Sie sicherstellen wollen, dass KEINE ANDEREN TASK in der Lage ist, ALLE Daten zu ändern, die Sie EXPLIZITERWEISE ERWARTEN, um stabil zu bleiben, können Sie es sich nicht leisten, Sperren freizugeben (was Commit macht).
Beachten Sie, dass während Sie eine Ressource sperren, andere Threads "warten, bis diese Ressource verfügbar wird". Die Wahrscheinlichkeit, dass dieser Stapel zum Zeitpunkt der Freigabe Ihrer Sperre nicht leer ist, wird höher, wenn die allgemeine Systemlast höher wird. Und was dein DBMS abschließt, wenn du (endlich) "commit" ausgibst, ist folgender Schluss: "Hey, wow, dieser Typ ist endlich mit dieser Ressource fertig, also kann ich jetzt alle anderen wartenden Typen versuchen lassen ihr Ding damit (UND es gibt nichts zu verhindern, "ihr Ding" von einem Update zu sein!) ".
Vielleicht gibt es Probleme mit der Snapshot-Isolation von Oracle, die ich übersehen habe. Entschuldigung wenn ja.