Ich erhalte eine ORA-01000 SQL-Ausnahme. Ich habe also einige Fragen dazu.
- Beziehen sich die maximal geöffneten Cursor genau auf die Anzahl der JDBC-Verbindungen oder auch auf die Anweisungs- und Ergebnismengenobjekte, die wir für eine einzelne Verbindung erstellt haben? (Wir verwenden Verbindungspool)
- Gibt es eine Möglichkeit, die Anzahl der Anweisungs- / Ergebnismengenobjekte in der Datenbank (wie Verbindungen) zu konfigurieren?
- Ist es ratsam, die Instanzvariablen Anweisung / Ergebnismenge Objekt anstelle der Methode lokale Anweisung / Ergebnismenge Objekt in einer Umgebung mit einem einzigen Thread zu verwenden?
Verursacht das Ausführen einer vorbereiteten Anweisung in einer Schleife dieses Problem? (Natürlich hätte ich auch sqlBatch verwenden können.) Hinweis: pStmt wird geschlossen, sobald die Schleife beendet ist.
{ //method try starts String sql = "INSERT into TblName (col1, col2) VALUES(?, ?)"; pStmt = obj.getConnection().prepareStatement(sql); pStmt.setLong(1, subscriberID); for (String language : additionalLangs) { pStmt.setInt(2, Integer.parseInt(language)); pStmt.execute(); } } //method/try ends { //finally starts pStmt.close() } //finally ends
Was passiert, wenn conn.createStatement () und conn.prepareStatement (sql) für ein einzelnes Verbindungsobjekt mehrmals aufgerufen werden?
Edit1: 6. Hilft die Verwendung des Referenzobjekts Weak / Soft bei der Verhinderung von Leckagen?
Edit2: 1. Kann ich auf irgendeine Weise alle fehlenden "statement.close ()" in meinem Projekt finden? Ich verstehe, dass es kein Speicherverlust ist. Aber ich muss eine Anweisungsreferenz finden (wo close () nicht ausgeführt wird), die für die Speicherbereinigung geeignet ist. Irgendein Werkzeug verfügbar? Oder muss ich es manuell analysieren?
Bitte helfen Sie mir, es zu verstehen.
Lösung
So finden Sie den geöffneten Cursor in Oracle DB für den Benutzernamen -VELU
Gehen Sie zur ORACLE-Maschine und starten Sie sqlplus als sysdba.
[oracle@db01 ~]$ sqlplus / as sysdba
Dann renne
SELECT A.VALUE,
S.USERNAME,
S.SID,
S.SERIAL#
FROM V$SESSTAT A,
V$STATNAME B,
V$SESSION S
WHERE A.STATISTIC# = B.STATISTIC#
AND S.SID = A.SID
AND B.NAME = 'opened cursors current'
AND USERNAME = 'VELU';
Wenn möglich, lesen Sie bitte meine Antwort, um meine Lösung besser zu verstehen
for (String language : additionalLangs) {
SYS.V$OPEN_CURSOR
Ansicht ansehen. Dadurch erhalten Sie nicht nur die SID, sondern auch den SQL-Text.Antworten:
ORA-01000, der Fehler mit maximal offenen Cursorn, ist ein äußerst häufiger Fehler bei der Entwicklung von Oracle-Datenbanken. Im Kontext von Java tritt dies auf, wenn die Anwendung versucht, mehr ResultSets zu öffnen, als auf einer Datenbankinstanz Cursor konfiguriert sind.
Häufige Ursachen sind:
Konfigurationsfehler
Lösung:
Cursorleck
Hintergrund
Dieser Abschnitt beschreibt einige der Theorien hinter Cursorn und wie JDBC verwendet werden sollte. Wenn Sie den Hintergrund nicht kennen müssen, können Sie dies überspringen und direkt zu "Beseitigung von Lecks" gehen.
Was ist ein Cursor?
Ein Cursor ist eine Ressource in der Datenbank, die den Status einer Abfrage enthält, insbesondere die Position, an der sich ein Leser in einem ResultSet befindet. Jede SELECT-Anweisung verfügt über einen Cursor, und gespeicherte PL / SQL-Prozeduren können so viele Cursor öffnen und verwenden, wie sie benötigen. Auf Orafaq erfahren Sie mehr über Cursor .
Eine Datenbankinstanz bedient normalerweise mehrere verschiedene Schemas , viele verschiedene Benutzer mit jeweils mehreren Sitzungen . Zu diesem Zweck steht eine feste Anzahl von Cursorn für alle Schemas, Benutzer und Sitzungen zur Verfügung. Wenn alle Cursor geöffnet sind (verwendet werden) und eine Anforderung eingeht, für die ein neuer Cursor erforderlich ist, schlägt die Anforderung mit einem ORA-010000-Fehler fehl.
Suchen und Einstellen der Anzahl der Cursor
Die Nummer wird normalerweise vom DBA bei der Installation konfiguriert. Auf die Anzahl der derzeit verwendeten Cursor, die maximale Anzahl und die Konfiguration kann in den Administratorfunktionen in Oracle SQL Developer zugegriffen werden . In SQL kann Folgendes festgelegt werden:
Verknüpfen von JDBC in der JVM mit Cursorn in der Datenbank
Die folgenden JDBC-Objekte sind eng mit den folgenden Datenbankkonzepten verbunden:
JDBC ist threadsicher: Es ist völlig in Ordnung, die verschiedenen JDBC-Objekte zwischen Threads zu übergeben.
Beispielsweise können Sie die Verbindung in einem Thread erstellen. Ein anderer Thread kann diese Verbindung verwenden, um ein PreparedStatement zu erstellen, und ein dritter Thread kann die Ergebnismenge verarbeiten. Die einzige wichtige Einschränkung besteht darin, dass nicht mehr als ein ResultSet gleichzeitig für ein einzelnes PreparedStatement geöffnet sein kann. Siehe Unterstützt Oracle DB mehrere (parallele) Vorgänge pro Verbindung?
Beachten Sie, dass ein Datenbank-Commit für eine Verbindung erfolgt und daher alle DMLs (INSERT, UPDATE und DELETE) für diese Verbindung zusammen festgeschrieben werden. Wenn Sie mehrere Transaktionen gleichzeitig unterstützen möchten, müssen Sie daher für jede gleichzeitige Transaktion mindestens eine Verbindung haben.
JDBC-Objekte schließen
Ein typisches Beispiel für die Ausführung eines ResultSet ist:
Beachten Sie, wie die finally-Klausel jede durch close () ausgelöste Ausnahme ignoriert:
In Java 7 hat Oracle die AutoCloseable-Oberfläche eingeführt, die den größten Teil der Java 6-Boilerplate durch einen schönen syntaktischen Zucker ersetzt.
JDBC-Objekte halten
JDBC-Objekte können sicher in lokalen Variablen, Objektinstanzen und Klassenmitgliedern gespeichert werden. Es ist im Allgemeinen besser zu praktizieren:
Es gibt jedoch eine Ausnahme: Wenn Sie EJBs oder einen Servlet / JSP-Container verwenden, müssen Sie einem strengen Threading-Modell folgen:
Leckagen beseitigen
Es gibt eine Reihe von Prozessen und Tools, mit denen JDBC-Lecks erkannt und beseitigt werden können:
Während der Entwicklung ist das frühzeitige Erkennen von Fehlern bei weitem der beste Ansatz:
Entwicklungspraktiken: Gute Entwicklungspraktiken sollten die Anzahl der Fehler in Ihrer Software verringern, bevor sie den Entwickler-Desk verlässt. Spezifische Praktiken umfassen:
Statische Code-Analyse: Verwenden Sie ein Tool wie die hervorragenden Findbugs , um eine statische Code-Analyse durchzuführen. Dies nimmt viele Stellen auf, an denen close () nicht korrekt behandelt wurde. Findbugs hat ein Plugin für Eclipse, läuft aber auch eigenständig für Einzelstücke und ist in Jenkins CI und andere Build-Tools integriert
Zur Laufzeit:
Haltbarkeit und Engagement
Protokollierung zur Laufzeit.
Sie können Ihrem Projekt einen JDBC-Debugging-Treiber hinzufügen (zum Debuggen - stellen Sie ihn nicht bereit). Ein Beispiel (ich habe es nicht verwendet) ist log4jdbc . Anschließend müssen Sie eine einfache Analyse dieser Datei durchführen, um festzustellen, welche Ausführungen keinen entsprechenden Abschluss haben. Das Zählen des Öffnens und Schließens sollte hervorheben, ob ein potenzielles Problem vorliegt
Andere Gedanken
Können Sie WeakReferences verwenden, um das Schließen von Verbindungen zu handhaben?
Schwache und weiche Referenzen ermöglichen es Ihnen, ein Objekt so zu referenzieren, dass die JVM den Referenten jederzeit mit Müll sammeln kann, wenn dies für angemessen erachtet wird (vorausgesetzt, es gibt keine starken Referenzketten für dieses Objekt).
Wenn Sie eine ReferenceQueue im Konstruktor an die weiche oder schwache Referenz übergeben, wird das Objekt in die ReferenceQueue gestellt, wenn das Objekt bei seinem Auftreten GC-geprüft wird (falls es überhaupt auftritt). Mit diesem Ansatz können Sie mit der Finalisierung des Objekts interagieren und das Objekt in diesem Moment schließen oder finalisieren.
Phantomreferenzen sind etwas seltsamer; Ihr Zweck ist nur die Steuerung der Finalisierung, aber Sie können niemals einen Verweis auf das ursprüngliche Objekt erhalten, daher wird es schwierig sein, die close () -Methode darauf aufzurufen.
Es ist jedoch selten eine gute Idee, zu versuchen, zu steuern, wann der GC ausgeführt wird (Schwache, weiche und Phantomreferenzen lassen Sie wissen, nachdem das Objekt für den GC in die Warteschlange gestellt wurde). Wenn der Speicher in der JVM groß ist (z. B. -Xmx2000m), wird das Objekt möglicherweise nie GC-fähig, und der ORA-01000 wird weiterhin angezeigt. Wenn der JVM-Speicher im Verhältnis zu den Anforderungen Ihres Programms klein ist, werden die Objekte ResultSet und PreparedStatement möglicherweise sofort nach der Erstellung (bevor Sie daraus lesen können) überprüft, was wahrscheinlich zu einem Fehler Ihres Programms führen wird.
TL; DR: Der schwache Referenzmechanismus ist keine gute Möglichkeit, Statement- und ResultSet-Objekte zu verwalten und zu schließen.
quelle
Ich füge ein paar weitere Erkenntnisse hinzu.
Loggin als sysdba.
In Putty (Oracle-Login):
In SqlPlus:
Nutzername:
sys as sysdba
Setzen Sie den Wert für session_cached_cursors auf 0, damit keine Cursor geschlossen werden.
Wählen Sie den vorhandenen OPEN_CURSORS-Wertesatz aus, der pro Verbindung in der Datenbank festgelegt wurde
Unten finden Sie die Abfrage, um die SID / Verbindungsliste mit geöffneten Cursorwerten zu finden.
Verwenden Sie die folgende Abfrage, um die SQLs in den geöffneten Cursorn zu identifizieren
Jetzt debuggen Sie den Code und genießen Sie !!! :) :)
quelle
Korrigieren Sie Ihren Code folgendermaßen:
Sind Sie sicher, dass Sie Ihre pStatements, Verbindungen und Ergebnisse wirklich schließen?
Um offene Objekte zu analysieren, können Sie ein Delegatormuster implementieren, das Code um Ihre Statemant-, Verbindungs- und Ergebnisobjekte legt. Sie werden also sehen, ob ein Objekt erfolgreich geschlossen wurde.
Ein Beispiel für: pStmt = obj. getConnection () .prepareStatement (sql);
quelle
Wenn es sich bei Ihrer Anwendung um eine Java EE-Anwendung handelt, die unter Oracle WebLogic als Anwendungsserver ausgeführt wird, ist die Einstellung für die Größe des Anweisungscaches in WebLogic eine mögliche Ursache für dieses Problem .
Wenn die Einstellung für die Größe des Anweisungscaches für eine bestimmte Datenquelle ungefähr gleich oder größer als die Einstellung für die maximale Anzahl offener Cursor in der Oracle-Datenbank ist, können alle offenen Cursor von zwischengespeicherten SQL-Anweisungen verwendet werden, die von WebLogic offen gehalten werden im ORA-01000 Fehler.
Um dies zu beheben, reduzieren Sie die Einstellung für die Größe des Anweisungscaches für jede WebLogic-Datenquelle, die auf die Oracle-Datenbank verweist, so, dass sie erheblich unter der Einstellung für die maximale Cursoranzahl in der Datenbank liegt.
In der WebLogic 10-Administratorkonsole finden Sie die Einstellung für die Größe des Anweisungscaches für jede Datenquelle unter Dienste (linke Navigation)> Datenquellen> (einzelne Datenquelle)> Registerkarte Verbindungspool.
quelle
Auch ich hatte dieses Problem. Die folgende Ausnahme kam früher
Ich habe Spring Framework mit Spring JDBC für die Dao-Ebene verwendet.
Meine Anwendung leckte Cursor irgendwie und nach ein paar Minuten gab es mir diese Ausnahme.
Nach vielen gründlichen Debugging- und Analysevorgängen stellte ich fest, dass in einer der Tabellen , die in der von mir ausgeführten Abfrage verwendet wurden, ein Problem mit der Indizierung, dem Primärschlüssel und den eindeutigen Einschränkungen auftrat .
Meine Anwendung hat versucht, die fälschlicherweise indizierten Spalten zu aktualisieren . Wenn meine Anwendung die Aktualisierungsabfrage für die indizierten Spalten traf, versuchte die Datenbank, die Neuindizierung basierend auf den aktualisierten Werten durchzuführen. Es leckte die Cursor .
Ich konnte das Problem lösen, indem ich die Spalten, die zur Suche in der Abfrage verwendet wurden, ordnungsgemäß indizierte und bei Bedarf geeignete Einschränkungen anwendete.
quelle
Ich hatte heute das gleiche Problem (ORA-01000). Ich hatte eine for-Schleife in try {}, um eine SELECT-Anweisung in einer Oracle-Datenbank viele Male auszuführen (jedes Mal, wenn ein Parameter geändert wurde), und schließlich {} hatte ich meinen Code, um Resultset, PreparedStatement und Connection wie gewohnt zu schließen . Sobald ich jedoch eine bestimmte Anzahl von Schleifen (1000) erreicht habe, wurde der Oracle-Fehler über zu viele offene Cursor angezeigt.
Basierend auf dem obigen Beitrag von Andrew Alcock habe ich Änderungen vorgenommen, sodass ich innerhalb der Schleife jede Ergebnismenge und jede Anweisung nach dem Abrufen der Daten und vor dem erneuten Schleifen geschlossen habe, wodurch das Problem gelöst wurde.
Darüber hinaus trat genau das gleiche Problem in einer anderen Schleife von Insert-Anweisungen in einer anderen Oracle-Datenbank (ORA-01000) auf, diesmal nach 300 Anweisungen. Wieder wurde es auf die gleiche Weise gelöst, sodass entweder das PreparedStatement oder das ResultSet oder beide als offene Cursor gelten, bis sie geschlossen werden.
quelle
Haben Sie autocommit = true gesetzt? Wenn nicht, versuchen Sie Folgendes:
quelle
Abfrage, um SQL zu finden, das geöffnet wurde.
quelle
Dieses Problem tritt hauptsächlich auf, wenn Sie das Verbindungspooling verwenden, da beim Schließen der Verbindung diese Verbindung zum Verbindungspool zurückkehrt und alle mit dieser Verbindung verknüpften Cursor niemals geschlossen werden, da die Verbindung zur Datenbank noch offen ist. Eine Alternative besteht darin, die Leerlaufverbindungszeit von Verbindungen im Pool zu verringern. Wenn also die Verbindung beispielsweise 10 Sekunden lang im Leerlauf ist, wird die Verbindung zur Datenbank geschlossen und eine neue Verbindung zum Einfügen in den Pool erstellt.
quelle
Die Verwendung der Stapelverarbeitung führt zu einem geringeren Overhead. Beispiele finden Sie unter folgendem Link: http://www.tutorialspoint.com/jdbc/jdbc-batch-processing.htm
quelle
In unserem Fall haben wir den Ruhezustand verwendet und es gab viele Variablen, die auf dieselbe zugeordnete Entität im Ruhezustand verweisen. Wir haben diese Referenzen in einer Schleife erstellt und gespeichert. Jede Referenz öffnete einen Cursor und hielt ihn offen.
Wir haben dies festgestellt, indem wir mithilfe einer Abfrage die Anzahl der geöffneten Cursor überprüft haben, während wir unseren Code ausgeführt haben, mit einem Debugger durchgegangen sind und selektiv Kommentare abgegeben haben.
Warum jede neue Referenz einen anderen Cursor öffnete - der fraglichen Entität waren Sammlungen anderer Entitäten zugeordnet, und ich denke, dies hatte etwas damit zu tun (vielleicht nicht nur dies allein, sondern in Kombination mit der Konfiguration des Abrufmodus und Cache-Einstellungen). Im Ruhezustand selbst gab es Fehler beim Öffnen geschlossener Cursor, obwohl diese in späteren Versionen behoben wurden.
Da wir sowieso nicht wirklich so viele doppelte Verweise auf dieselbe Entität haben mussten, bestand die Lösung darin, nicht mehr all diese redundanten Verweise zu erstellen und zu behalten. Einmal haben wir das Problem gemacht, wenn wir weg waren.
quelle
Ich hatte dieses Problem mit meiner Datenquelle in WildFly und Tomcat, die eine Verbindung zu einem Oracle 10g herstellte.
Ich stellte fest, dass die Anweisung unter bestimmten Bedingungen nicht geschlossen wurde, selbst wenn die Anweisung.close () aufgerufen wurde. Das Problem war mit dem von uns verwendeten Oracle-Treiber: ojdbc7.jar. Dieser Treiber ist für Oracle 12c und 11g vorgesehen und es scheint einige Probleme zu geben, wenn er mit Oracle 10g verwendet wird. Daher habe ich ein Downgrade auf ojdbc5.jar durchgeführt und jetzt läuft alles einwandfrei.
quelle
Ich hatte das gleiche Problem, weil ich db für mehr als 1000 Iterationen abgefragt habe. Ich habe try und schließlich in meinem Code verwendet. Wurde aber immer noch fehlerhaft.
Um dies zu lösen, habe ich mich gerade bei oracle db angemeldet und die folgende Abfrage ausgeführt:
ALTER SYSTEM SET open_cursors = 8000 SCOPE = BOTH;
Und das hat mein Problem sofort gelöst.
quelle