java.sql.SQLException: - ORA-01000: numero massimo di cursori aperti superato


115

Ricevo un'eccezione SQL ORA-01000. Quindi ho alcune domande relative ad esso.

  1. Il numero massimo di cursori aperti è esattamente correlato al numero di connessioni JDBC o sono anche correlati all'istruzione e agli oggetti del gruppo di risultati che abbiamo creato per una singola connessione? (Stiamo usando un pool di connessioni)
  2. C'è un modo per configurare il numero di oggetti istruzione / gruppo di risultati nel database (come le connessioni)?
  3. È consigliabile utilizzare l'istruzione della variabile di istanza / l'oggetto gruppo di risultati invece dell'istruzione locale del metodo / l'oggetto gruppo di risultati in un ambiente a thread singolo?
  4. L'esecuzione di un'istruzione preparata in un ciclo causa questo problema? (Ovviamente, avrei potuto usare sqlBatch) Nota: pStmt viene chiuso una volta che il ciclo è finito.

    { //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 
    
  5. Cosa succederà se conn.createStatement () e conn.prepareStatement (sql) vengono chiamati più volte su un singolo oggetto di connessione?

Edit1: 6. L'uso di un oggetto dell'istruzione di riferimento debole / debole aiuterà a prevenire la perdita?

Edit2: 1. C'è un modo per trovare tutte le "statement.close ()" mancanti nel mio progetto? Capisco che non è una perdita di memoria. Ma ho bisogno di trovare un riferimento all'istruzione (dove close () non viene eseguito) idoneo per la garbage collection? Qualche strumento disponibile? Oppure devo analizzarlo manualmente?

Per favore aiutami a capirlo.

Soluzione

Per trovare il cursore aperto in Oracle DB per nome utente -VELU

Vai alla macchina ORACLE e avvia sqlplus come sysdba.

[oracle@db01 ~]$ sqlplus / as sysdba 

Allora corri

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';

Se possibile, leggi la mia risposta per una maggiore comprensione della mia soluzione


Puoi pubblicare il tuo codice completo? Sarebbe interessante vedere dove stai chiudendo le parentesi graffe aperte perfor (String language : additionalLangs) {
Jåcob

@ Kanagavelu Sugumar: perché non fare 5 domande diverse in SO?
Jayan

1
Ecco una risposta che ho trovato molto utile: stackoverflow.com/a/4507507/501113
chaotic3quilibrium

Verifica se la risposta è utile: stackoverflow.com/questions/34716456/…
Manu

Per rintracciare i cursori aperti in Oracle, potresti anche voler dare un'occhiata alla SYS.V$OPEN_CURSORvista. Questo ti darà non solo il SID, ma anche il testo SQL.
Basso

Risposte:


290

ORA-01000, l'errore di massima apertura dei cursori, è un errore estremamente comune nello sviluppo del database Oracle. Nel contesto di Java, si verifica quando l'applicazione tenta di aprire più ResultSet di quanti siano i cursori configurati su un'istanza di database.

Le cause comuni sono:

  1. Errore di configurazione

    • Hai più thread nella tua applicazione che interrogano il database che cursori sul DB. Un caso è quello in cui si dispone di una connessione e di un pool di thread più grande del numero di cursori nel database.
    • Hai molti sviluppatori o applicazioni connesse alla stessa istanza database (che probabilmente includerà molti schemi) e insieme stai utilizzando troppe connessioni.
    • Soluzione:

  2. Perdita del cursore

    • Le applicazioni non chiudono i ResultSet (in JDBC) oi cursori (nelle procedure memorizzate sul database)
    • Soluzione : le perdite del cursore sono bug; l'aumento del numero di cursori sul DB ritarda semplicemente l'inevitabile guasto. Le perdite possono essere trovate utilizzando l' analisi statica del codice , la registrazione JDBC o a livello di applicazione e il monitoraggio del database .

sfondo

Questa sezione descrive alcune delle teorie alla base dei cursori e come dovrebbe essere usato JDBC. Se non hai bisogno di conoscere lo sfondo, puoi saltare questo passaggio e andare direttamente a "Eliminazione delle perdite".

Cos'è un cursore?

Un cursore è una risorsa nel database che contiene lo stato di una query, in particolare la posizione in cui si trova un lettore in un ResultSet. Ogni istruzione SELECT dispone di un cursore e le stored procedure PL / SQL possono essere aperte e utilizzare tutti i cursori necessari. Puoi trovare ulteriori informazioni sui cursori su Orafaq .

Un'istanza di database in genere serve diversi schemi diversi , molti utenti diversi ciascuno con più sessioni . Per fare ciò, ha un numero fisso di cursori disponibili per tutti gli schemi, utenti e sessioni. Quando tutti i cursori sono aperti (in uso) e arriva una richiesta che richiede un nuovo cursore, la richiesta non riesce con un errore ORA-010000.

Trovare e impostare il numero di cursori

Il numero è normalmente configurato dal DBA durante l'installazione. Il numero di cursori attualmente in uso, il numero massimo e la configurazione sono accessibili nelle funzioni di amministratore in Oracle SQL Developer . Da SQL può essere impostato con:

ALTER SYSTEM SET OPEN_CURSORS=1337 SID='*' SCOPE=BOTH;

Correlare JDBC nella JVM ai cursori nel DB

Gli oggetti JDBC di seguito sono strettamente collegati ai seguenti concetti di database:

  • JDBC Connection è la rappresentazione client di una sessione di database e fornisce le transazioni di database . Una connessione può avere solo una singola transazione aperta alla volta (ma le transazioni possono essere nidificate)
  • Un ResultSet JDBC è supportato da un singolo cursore nel database. Quando close () viene chiamato sul ResultSet, il cursore viene rilasciato.
  • Una CallableStatement JDBC richiama una procedura memorizzata sul database, spesso scritta in PL / SQL. La procedura memorizzata può creare zero o più cursori e può restituire un cursore come ResultSet JDBC.

JDBC è thread-safe: è abbastanza OK passare i vari oggetti JDBC tra i thread.

Ad esempio, puoi creare la connessione in un thread; un altro thread può utilizzare questa connessione per creare un PreparedStatement e un terzo thread può elaborare il set di risultati. L'unica limitazione principale è che non è possibile avere più di un ResultSet aperto su un singolo PreparedStatement in qualsiasi momento. Vedi Oracle DB supporta più operazioni (parallele) per connessione?

Si noti che un commit del database si verifica su una connessione, quindi tutti i DML (INSERT, UPDATE e DELETE) su quella connessione eseguiranno il commit insieme. Pertanto, se si desidera supportare più transazioni contemporaneamente, è necessario disporre di almeno una connessione per ciascuna transazione simultanea.

Chiusura di oggetti JDBC

Un tipico esempio di esecuzione di un ResultSet è:

Statement stmt = conn.createStatement();
try {
    ResultSet rs = stmt.executeQuery( "SELECT FULL_NAME FROM EMP" );
    try {
        while ( rs.next() ) {
            System.out.println( "Name: " + rs.getString("FULL_NAME") );
        }
    } finally {
        try { rs.close(); } catch (Exception ignore) { }
    }
} finally {
    try { stmt.close(); } catch (Exception ignore) { }
}

Nota come la clausola finalmente ignori qualsiasi eccezione sollevata da close ():

  • Se si chiude semplicemente il ResultSet senza provare {} catch {}, potrebbe non riuscire e impedire la chiusura dell'istruzione
  • Vogliamo consentire a qualsiasi eccezione sollevata nel corpo del tentativo di propagarsi al chiamante. Se hai un ciclo, ad esempio, creando ed eseguendo istruzioni, ricordati di chiudere ogni istruzione all'interno del ciclo.

In Java 7, Oracle ha introdotto l' interfaccia AutoCloseable che sostituisce la maggior parte del boilerplate Java 6 con un po 'di piacevole zucchero sintattico.

Tenere oggetti JDBC

Gli oggetti JDBC possono essere contenuti in modo sicuro in variabili locali, istanze di oggetti e membri di classi. In genere è meglio pratica:

  • Utilizza l'istanza dell'oggetto o i membri della classe per conservare oggetti JDBC riutilizzati più volte per un periodo più lungo, come Connections e PreparedStatement
  • Utilizzare le variabili locali per i ResultSet poiché questi vengono ottenuti, ripetuti e quindi chiusi normalmente nell'ambito di una singola funzione.

Esiste, tuttavia, un'eccezione: se si utilizzano EJB o un contenitore Servlet / JSP, è necessario seguire un modello di threading rigoroso:

  • Solo il server delle applicazioni crea i thread (con i quali gestisce le richieste in arrivo)
  • Solo il server delle applicazioni crea le connessioni (ottenute dal pool di connessioni)
  • Quando salvi i valori (stato) tra le chiamate, devi stare molto attento. Non archiviare mai valori nelle proprie cache o membri statici: ciò non è sicuro tra cluster e altre condizioni strane e il server delle applicazioni potrebbe fare cose terribili ai dati. Utilizza invece bean stateful o un database.
  • In particolare, non tenere mai oggetti JDBC (connessioni, ResultSet, PreparedStatement, ecc.) Su diverse chiamate remote: lasciare che sia il server delle applicazioni a gestirlo. Il server delle applicazioni non solo fornisce un pool di connessioni, ma memorizza anche nella cache le PreparedStatement.

Eliminare le perdite

Sono disponibili numerosi processi e strumenti per aiutare a rilevare ed eliminare le fughe di JDBC:

  1. Durante lo sviluppo, individuare tempestivamente i bug è di gran lunga l'approccio migliore:

    1. Pratiche di sviluppo: buone pratiche di sviluppo dovrebbero ridurre il numero di bug nel software prima che lasci la scrivania dello sviluppatore. Le pratiche specifiche includono:

      1. Programmazione in coppia , per educare chi non ha esperienza sufficiente
      2. Revisioni del codice perché molti occhi sono meglio di uno
      3. Test unitario, il che significa che puoi esercitare qualsiasi codice di base da uno strumento di test che rende banale la riproduzione delle perdite
      4. Usa le librerie esistenti per il pool di connessioni piuttosto che crearne di tue
    2. Analisi statica del codice: utilizza uno strumento come l'eccellente Findbugs per eseguire un'analisi statica del codice. Questo rileva molti punti in cui close () non è stato gestito correttamente. Findbugs ha un plug-in per Eclipse, ma funziona anche da solo per una tantum, ha integrazioni in Jenkins CI e altri strumenti di compilazione

  2. In fase di esecuzione:

    1. Holdability e impegno

      1. Se la conservazione del ResultSet è ResultSet.CLOSE_CURSORS_OVER_COMMIT, il ResultSet viene chiuso quando viene chiamato il metodo Connection.commit (). Questo può essere impostato utilizzando Connection.setHoldability () o utilizzando il metodo Connection.createStatement () sovraccarico.
    2. Registrazione in fase di esecuzione.

      1. Metti buone dichiarazioni di log nel tuo codice. Questi dovrebbero essere chiari e comprensibili in modo che il cliente, il personale di supporto ei membri del team possano capire senza formazione. Dovrebbero essere concisi e includere la stampa dei valori interni / di stato delle variabili e degli attributi chiave in modo da poter tracciare la logica di elaborazione. Una buona registrazione è fondamentale per il debug delle applicazioni, in particolare quelle che sono state distribuite.
      2. Puoi aggiungere un driver JDBC di debug al tuo progetto (per il debug, non distribuirlo effettivamente). Un esempio (non l'ho usato) è log4jdbc . È quindi necessario eseguire alcune semplici analisi su questo file per vedere quali esecuzioni non hanno una chiusura corrispondente. Contare l'apertura e la chiusura dovrebbe evidenziare se c'è un potenziale problema

        1. Monitoraggio del database. Monitorare l'applicazione in esecuzione utilizzando strumenti quali la funzione "Monitor SQL" di SQL Developer o il TOAD di Quest . Il monitoraggio è descritto in questo articolo . Durante il monitoraggio, interroghi i cursori aperti (ad esempio dalla tabella v $ sesstat) e rivedi il loro SQL. Se il numero di cursori aumenta e (cosa più importante) viene dominato da un'istruzione SQL identica, sai di avere una perdita con quell'SQL. Cerca il tuo codice e rivedi.

Altri pensieri

Puoi usare WeakReferences per gestire la chiusura delle connessioni?

I riferimenti deboli e morbidi sono modi per consentire di fare riferimento a un oggetto in un modo che consente alla JVM di raccogliere in modo inutile il referente in qualsiasi momento lo ritenga adatto (supponendo che non ci siano catene di riferimento forti a quell'oggetto).

Se si passa una ReferenceQueue nel costruttore al riferimento debole o debole, l'oggetto viene posizionato in ReferenceQueue quando l'oggetto viene sottoposto a GC quando si verifica (se si verifica affatto). Con questo approccio, puoi interagire con la finalizzazione dell'oggetto e puoi chiudere o finalizzare l'oggetto in quel momento.

I riferimenti fantasma sono un po 'più strani; il loro scopo è solo quello di controllare la finalizzazione, ma non puoi mai ottenere un riferimento all'oggetto originale, quindi sarà difficile chiamare il metodo close () su di esso.

Tuttavia, raramente è una buona idea tentare di controllare quando il GC è in esecuzione (Weak, Soft e PhantomReferences ti informano dopo il fatto che l'oggetto è stato accodato per GC). In effetti, se la quantità di memoria nella JVM è grande (es. -Xmx2000m) potresti non mettere mai in GC l'oggetto e continuerai a sperimentare ORA-01000. Se la memoria JVM è piccola rispetto ai requisiti del programma, è possibile che gli oggetti ResultSet e PreparedStatement vengano sottoposti a GC immediatamente dopo la creazione (prima che sia possibile leggere da essi), il che probabilmente fallirà il programma.

TL; DR: il meccanismo di riferimento debole non è un buon modo per gestire e chiudere gli oggetti Statement e ResultSet.


3
Se crei istruzioni in un ciclo, assicurati che sia chiuso nel ciclo altrimenti finirai per chiudere solo l'ultima istruzione.
basiljames

Grazie, basiljames. Ho appena modificato la risposta per aggiungere il punto che hai sollevato.
Andrew Alcock

@ Andrew Alcock Grazie mille! Andrea. Potrebbe per favore rispondere anche al 6 °.
Kanagavelu Sugumar

@ AndrewAlcock Per favore .. per favore .. per favore .. rispondi anche alla mia settima domanda. Dal momento che il nostro progetto stiamo affrontando ORA-01000 molto frequentemente durante il test di carico. I tuoi input sono più preziosi per me. Grazie mille in anticipo !!
Kanagavelu Sugumar

RE: 7 - puoi provare la ricerca di prossimità utilizzando uno strumento come grep. Quando riconosci un codice SQL (seleziona, inserisci, aggiorna, elimina), osserva la prossimità della parola close () accanto all'istruzione. Se la vicinanza è più lontana del previsto, potrebbe essere un modo per indagare su dove manca. lightboxtechnologies.com/2012/07/27/…
Dom

28

Aggiungo qualche altra comprensione.

  1. Il cursore riguarda solo una dichiarazione objecct; Non è né resultSet né l'oggetto connessione.
  2. Ma dobbiamo ancora chiudere il set di risultati per liberare un po 'di memoria Oracle. Tuttavia, se non chiudi il set di risultati che non verrà conteggiato per CURSORS.
  3. L'oggetto istruzione di chiusura chiuderà automaticamente anche l'oggetto gruppo di risultati.
  4. Il cursore verrà creato per tutte le istruzioni SELECT / INSERT / UPDATE / DELETE.
  5. Ogni istanza database ORACLE può essere identificata utilizzando Oracle SID; allo stesso modo ORACLE DB può identificare ogni connessione utilizzando il SID della connessione. Entrambi i SID sono diversi.
  6. Quindi la sessione ORACLE non è altro che una connessione jdbc (tcp); che non è altro che un SID.
  7. Se impostiamo il numero massimo di cursori su 500, è solo per una sessione / connessione / SID JDBC.
  8. Quindi possiamo avere molte connessioni JDBC con il rispettivo numero di cursori (istruzioni).
  9. Una volta terminata la JVM, tutte le connessioni / cursori verranno chiuse, OPPURE JDBCConnection verrà chiusa I CURSORI rispetto a quella connessione verranno chiusi.

Accesso come sysdba.

In Putty (accesso Oracle):

  [oracle@db01 ~]$ sqlplus / as sysdba

In SqlPlus:

Nome utente: sys as sysdba

Imposta il valore session_cached_cursors su 0 in modo che non abbia cursori chiusi.

 alter session set session_cached_cursors=0
 select * from V$PARAMETER where name='session_cached_cursors'

Seleziona il set di valori OPEN_CURSORS esistente per connessione nel DB

 SELECT max(a.value) as highest_open_cur, p.value as max_open_cur FROM v$sesstat a, v$statname b, v$parameter p WHERE a.statistic# = b.statistic# AND b.name = 'opened cursors current' AND p.name= 'open_cursors'  GROUP BY p.value;

Di seguito è riportata la query per trovare l'elenco SID / connessioni con i valori del cursore aperto.

 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 = 'SCHEMA_NAME_IN_CAPS'

Usa la query seguente per identificare gli sql nei cursori aperti

 SELECT oc.sql_text, s.sid 
 FROM v$open_cursor oc, v$session s
 WHERE OC.sid = S.sid
 AND s.sid=1604
 AND OC.USER_NAME ='SCHEMA_NAME_IN_CAPS'

Ora esegui il debug del codice e divertiti !!! :)


1
Ecco un'altra query che sembra funzionare bene: stackoverflow.com/a/2560415/32453
rogerdpack

4

Correggi il tuo codice in questo modo:

try
{ //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
{ //finally starts
   pStmt.close()
} 

Sei sicuro di chiudere davvero le tue dichiarazioni, connessioni e risultati?

Per analizzare gli oggetti aperti è possibile impiantare un pattern delegatore, che avvolge il codice attorno al proprio stato, connessione e oggetti risultato. Quindi vedrai se un oggetto verrà chiuso con successo.

Un esempio per: pStmt = obj. getConnection () .prepareStatement (sql);

    class obj{ 

    public Connection getConnection(){
    return new ConnectionDelegator(...here create your connection object and put it into ...);

    } 
}


class ConnectionDelegator implements Connection{
    Connection delegates;

    public ConnectionDelegator(Connection con){
       this.delegates = con;
    }

    public Statement prepareStatement(String sql){
        return delegates.prepareStatement(sql);
    }

    public void close(){
        try{
           delegates.close();
        }finally{
           log.debug(delegates.toString() + " was closed");
        }
    }
}

3

Se l'applicazione è un'applicazione Java EE in esecuzione su Oracle WebLogic come server delle applicazioni, una possibile causa di questo problema è l' impostazione Dimensioni cache istruzioni in WebLogic.

Se l'impostazione Dimensioni cache istruzioni per una particolare origine dati è circa uguale o superiore all'impostazione del numero massimo di cursori aperti del database Oracle, tutti i cursori aperti possono essere utilizzati dalle istruzioni SQL memorizzate nella cache che vengono mantenute aperte da WebLogic, risultando nell'errore ORA-01000.

Per risolvere questo problema, ridurre l'impostazione Dimensioni cache istruzioni per ciascuna origine dati WebLogic che punta al database Oracle in modo che sia notevolmente inferiore all'impostazione del numero massimo di cursori sul database.

Nella console di amministrazione di WebLogic 10, l'impostazione Dimensioni cache istruzioni per ciascuna origine dati è disponibile in Servizi (menu di navigazione sinistro)> Origini dati> (origine dati singola)> scheda Pool di connessione.


1
Hibernate ha anche una cache delle istruzioni. Vedi anche developer.jboss.org/wiki/…
Pino

3

Anch'io avevo affrontato questo problema. L'eccezione di seguito era arrivata

java.sql.SQLException: - ORA-01000: maximum open cursors exceeded

Stavo usando Spring Framework con Spring JDBC per il livello dao.

La mia applicazione in qualche modo perdeva i cursori e dopo pochi minuti circa, mi dava questa eccezione.

Dopo un sacco di debug e analisi approfonditi, ho scoperto che c'era il problema con l' indicizzazione, la chiave primaria e i vincoli univoci in una delle tabelle utilizzate nella query che stavo eseguendo.

La mia applicazione stava tentando di aggiornare le colonne che erano state indicizzate per errore . Quindi, ogni volta che la mia applicazione premeva la query di aggiornamento sulle colonne indicizzate, il database cercava di eseguire la reindicizzazione in base ai valori aggiornati. Stava perdendo i cursori .

Sono stato in grado di risolvere il problema eseguendo un'indicizzazione corretta sulle colonne utilizzate per la ricerca nella query e applicando i vincoli appropriati laddove richiesto.


2

Oggi ho affrontato lo stesso problema (ORA-01000). Avevo un ciclo for nel tentativo {}, per eseguire un'istruzione SELECT in un DB Oracle molte volte (ogni volta cambiando un parametro), e alla fine {} avevo il mio codice per chiudere Resultset, PreparedStatement e Connection come al solito . Ma non appena ho raggiunto un numero specifico di cicli (1000) ho ricevuto l'errore Oracle su troppi cursori aperti.

Sulla base del post di Andrew Alcock sopra, ho apportato modifiche in modo che all'interno del ciclo, ho chiuso ogni gruppo di risultati e ogni istruzione dopo aver ottenuto i dati e prima di ripetere il ciclo, e questo ha risolto il problema.

Inoltre, lo stesso identico problema si è verificato in un altro ciclo di istruzioni di inserimento, in un altro DB Oracle (ORA-01000), questa volta dopo 300 istruzioni. Anche in questo caso è stato risolto allo stesso modo, quindi PreparedStatement o ResultSet o entrambi contano come cursori aperti finché non vengono chiusi.


Non mi sembra giusto. Spring documenta che è responsabile della chiusura dei ResultSet ( docs.spring.io/spring/docs/current/spring-framework-reference/… ).
Ryan

solo per chiarimento, in quegli esempi non stavo usando Spring.
Kinnison84

1

Hai impostato autocommit = true? In caso contrario, prova questo:

{ //method try starts  
    String sql = "INSERT into TblName (col1, col2) VALUES(?, ?)";
    Connection conn = obj.getConnection()
    pStmt = conn.prepareStatement(sql);

    for (String language : additionalLangs) {
        pStmt.setLong(1, subscriberID);
        pStmt.setInt(2, Integer.parseInt(language));
        pStmt.execute();
        conn.commit();
    }
} //method/try ends { 
    //finally starts
    pStmt.close()
} //finally ends 

Potresti rispondere anche alle altre domande?
Kanagavelu Sugumar

2
Autocommit non chiude le connessioni: esegue il commit automatico di ogni istruzione immediatamente dopo l'esecuzione. Se stai usando autocommit non stai ottenendo valore da una delle proprietà più importanti del database: le transazioni. Potresti invece considerare di utilizzare un database NoSQL.
Andrew Alcock

1

query per trovare sql che ha aperto.

SELECT s.machine, oc.user_name, oc.sql_text, count(1) 
FROM v$open_cursor oc, v$session s
WHERE oc.sid = s.sid
and S.USERNAME='XXXX'
GROUP BY user_name, sql_text, machine
HAVING COUNT(1) > 2
ORDER BY count(1) DESC

1

Questo problema si verifica principalmente quando si utilizza il pool di connessioni perché quando si chiude la connessione quella connessione torna al pool di connessioni e tutti i cursori associati a quella connessione non vengono mai chiusi poiché la connessione al database è ancora aperta. Quindi un'alternativa è ridurre il tempo di connessione inattiva delle connessioni nel pool, quindi ogni volta che la connessione rimane inattiva in connessione per diciamo 10 secondi, la connessione al database verrà chiusa e verrà creata una nuova connessione da inserire nel pool.



0

Nel nostro caso, stavamo usando Hibernate e avevamo molte variabili che facevano riferimento alla stessa entità mappata Hibernate. Stavamo creando e salvando questi riferimenti in un ciclo. Ogni riferimento ha aperto un cursore e lo ha mantenuto aperto.

Lo abbiamo scoperto utilizzando una query per controllare il numero di cursori aperti durante l'esecuzione del nostro codice, eseguendo un debugger e commentando selettivamente le cose.

Per quanto riguarda il motivo per cui ogni nuovo riferimento ha aperto un altro cursore: l'entità in questione aveva raccolte di altre entità mappate su di essa e penso che questo avesse qualcosa a che fare con esso (forse non solo questo da solo, ma in combinazione con il modo in cui avevamo configurato la modalità di recupero e impostazioni della cache). Hibernate stesso ha avuto dei bug che non riuscivano a chiudere i cursori aperti, anche se sembra che questi siano stati corretti nelle versioni successive.

Dal momento che non avevamo davvero bisogno di avere così tanti riferimenti duplicati alla stessa entità, la soluzione era smettere di creare e mantenere tutti quei riferimenti ridondanti. Una volta che abbiamo risolto il problema quando siamo via.


0

Ho avuto questo problema con la mia origine dati in WildFly e Tomcat, connettendomi a un Oracle 10g.

Ho scoperto che in determinate condizioni l'istruzione non era chiusa anche quando veniva richiamata statement.close (). Il problema era con il driver Oracle che stavamo utilizzando: ojdbc7.jar. Questo driver è destinato a Oracle 12c e 11g e sembra che abbia alcuni problemi quando viene utilizzato con Oracle 10g, quindi eseguo il downgrade a ojdbc5.jar e ora tutto funziona correttamente.


0

Ho affrontato lo stesso problema perché stavo interrogando db per più di 1000 iterazioni. Ho usato try e finalmente nel mio codice. Ma continuava a ricevere errori.

Per risolvere questo problema, ho appena effettuato l'accesso a Oracle db e ho eseguito la query seguente:

ALTER SYSTEM SET open_cursors = 8000 SCOPE = BOTH;

E questo ha risolto immediatamente il mio problema.


Questo ha risolto alcuni sintomi ma in realtà non ha risolto il problema. È necessario correggere il codice in modo che chiuda i cursori una volta terminato con essi.
APC
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.