java.sql.SQLException: - ORA-01000: se excedió el máximo de cursores abiertos

115

Recibo una excepción SQL ORA-01000. Entonces tengo algunas consultas relacionadas.

  1. ¿Están los cursores abiertos máximos relacionados exactamente con la cantidad de conexiones JDBC, o también están relacionados con la declaración y los objetos del conjunto de resultados que hemos creado para una sola conexión? (Estamos usando un grupo de conexiones)
  2. ¿Hay alguna forma de configurar el número de objetos de declaración / conjunto de resultados en la base de datos (como conexiones)?
  3. ¿Es aconsejable utilizar una declaración de variable de instancia / objeto de conjunto de resultados en lugar de una declaración local de método / objeto de conjunto de resultados en un entorno de un solo subproceso?
  4. ¿La ejecución de una declaración preparada en un bucle causa este problema? (Por supuesto, podría haber usado sqlBatch) Nota: pStmt se cierra una vez que finaliza el ciclo.

    { //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. ¿Qué pasará si conn.createStatement () y conn.prepareStatement (sql) se llaman varias veces en un solo objeto de conexión?

Edit1: 6. ¿El uso del objeto de declaración de referencia Débil / Suave ayudará a prevenir la fuga?

Edit2: 1. ¿Hay alguna manera de encontrar todas las "statement.close ()" que faltan en mi proyecto? Entiendo que no es una pérdida de memoria. ¿Pero necesito encontrar una referencia de declaración (donde no se realiza close ()) elegible para la recolección de basura? ¿Alguna herramienta disponible? ¿O tengo que analizarlo manualmente?

Por favor ayúdame a entenderlo.

Solución

Para encontrar el cursor abierto en Oracle DB para el nombre de usuario -VELU

Vaya a la máquina ORACLE e inicie sqlplus como sysdba.

[oracle@db01 ~]$ sqlplus / as sysdba 

Entonces corre

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

Si es posible, lea mi respuesta para comprender mejor mi solución

Kanagavelu Sugumar
fuente
¿Puedes publicar tu código completo? Sería interesante ver dónde está cerrando las llaves de apertura abiertas parafor (String language : additionalLangs) {
Jåcob
@ Kanagavelu Sugumar: ¿por qué no hacer 5 preguntas diferentes en SO?
Jayan
1
Aquí hay una respuesta que encontré muy útil: stackoverflow.com/a/4507507/501113
chaotic3quilibrium
Vea si la respuesta es útil: stackoverflow.com/questions/34716456/…
Manu
Para rastrear cursores abiertos en Oracle, es posible que también desee echar un vistazo a la SYS.V$OPEN_CURSORvista. Esto le dará no solo el SID, sino también el texto SQL.
Bass

Respuestas:

290

ORA-01000, el error máximo de cursores abiertos, es un error extremadamente común en el desarrollo de bases de datos Oracle. En el contexto de Java, ocurre cuando la aplicación intenta abrir más ResultSets que cursores configurados en una instancia de base de datos.

Las causas comunes son:

  1. Error de configuración

    • Tiene más subprocesos en su aplicación que consultan la base de datos que cursores en la base de datos. Un caso es cuando tiene una conexión y un grupo de subprocesos mayor que el número de cursores en la base de datos.
    • Tiene muchos desarrolladores o aplicaciones conectados a la misma instancia de base de datos (que probablemente incluirá muchos esquemas) y juntos están usando demasiadas conexiones.
    • Solución:

  2. Fuga del cursor

    • Las aplicaciones no cierran ResultSets (en JDBC) o cursores (en procedimientos almacenados en la base de datos)
    • Solución : las fugas del cursor son errores; aumentar el número de cursores en la base de datos simplemente retrasa la falla inevitable. Las fugas se pueden encontrar mediante el análisis de código estático , JDBC o el registro a nivel de aplicación y la supervisión de la base de datos .

Antecedentes

Esta sección describe parte de la teoría detrás de los cursores y cómo se debe usar JDBC. Si no necesita conocer los antecedentes, puede omitir esto e ir directamente a 'Eliminación de fugas'.

¿Qué es un cursor?

Un cursor es un recurso en la base de datos que contiene el estado de una consulta, específicamente la posición en la que se encuentra un lector en un ResultSet. Cada instrucción SELECT tiene un cursor, y los procedimientos almacenados PL / SQL pueden abrir y usar tantos cursores como necesiten. Puede encontrar más información sobre los cursores en Orafaq .

Una instancia de base de datos normalmente sirve a varios esquemas diferentes , muchos usuarios diferentes , cada uno con varias sesiones . Para ello, dispone de un número fijo de cursores disponibles para todos los esquemas, usuarios y sesiones. Cuando todos los cursores están abiertos (en uso) y entra una solicitud que requiere un nuevo cursor, la solicitud falla con un error ORA-010000.

Encontrar y configurar el número de cursores

El DBA normalmente configura el número durante la instalación. Se puede acceder al número de cursores actualmente en uso, el número máximo y la configuración en las funciones de Administrador en Oracle SQL Developer . Desde SQL se puede configurar con:

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

Relacionar JDBC en la JVM con cursores en la base de datos

Los siguientes objetos JDBC están estrechamente relacionados con los siguientes conceptos de base de datos:

  • JDBC Connection es la representación del cliente de una sesión de base de datos y proporciona transacciones de base de datos . Una conexión solo puede tener una única transacción abierta a la vez (pero las transacciones se pueden anidar)
  • Un ResultSet de JDBC es compatible con un solo cursor en la base de datos. Cuando se llama a close () en ResultSet, se suelta el cursor.
  • Un JDBC CallableStatement invoca un procedimiento almacenado en la base de datos, a menudo escrito en PL / SQL. El procedimiento almacenado puede crear cero o más cursores y puede devolver un cursor como un conjunto de resultados JDBC.

JDBC es seguro para subprocesos: está bastante bien pasar varios objetos JDBC entre subprocesos.

Por ejemplo, puede crear la conexión en un hilo; otro hilo puede usar esta conexión para crear un PreparedStatement y un tercer hilo puede procesar el conjunto de resultados. La única restricción principal es que no puede tener más de un ResultSet abierto en un solo PreparedStatement en cualquier momento. Consulte ¿Oracle DB admite varias operaciones (paralelas) por conexión?

Tenga en cuenta que se produce una confirmación de base de datos en una conexión, por lo que todos los DML (INSERT, UPDATE y DELETE) en esa conexión se confirmarán juntos. Por lo tanto, si desea admitir varias transacciones al mismo tiempo, debe tener al menos una conexión para cada transacción simultánea.

Cerrar objetos JDBC

Un ejemplo típico de ejecución de un ResultSet es:

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) { }
}

Tenga en cuenta cómo la cláusula finalmente ignora cualquier excepción generada por close ():

  • Si simplemente cierra ResultSet sin el try {} catch {}, puede fallar y evitar que se cierre la declaración.
  • Queremos permitir que cualquier excepción que surja en el cuerpo del intento se propague al llamador. Si tiene un bucle, por ejemplo, para crear y ejecutar declaraciones, recuerde cerrar cada declaración dentro del bucle.

En Java 7, Oracle ha introducido la interfaz AutoCloseable que reemplaza la mayor parte del texto estándar de Java 6 con un agradable azúcar sintáctico.

Sosteniendo objetos JDBC

Los objetos JDBC pueden guardarse de forma segura en variables locales, instancias de objetos y miembros de clases. En general, es una mejor práctica:

  • Utilice la instancia de objeto o los miembros de la clase para contener los objetos JDBC que se reutilizan varias veces durante un período más largo, como Connections y PreparedStatements
  • Utilice variables locales para ResultSets, ya que se obtienen, se repiten y luego se cierran normalmente dentro del alcance de una única función.

Sin embargo, hay una excepción: si está utilizando EJB, o un contenedor Servlet / JSP, debe seguir un modelo de subprocesamiento estricto:

  • Solo el servidor de aplicaciones crea subprocesos (con los que maneja las solicitudes entrantes)
  • Solo el servidor de aplicaciones crea conexiones (que obtiene del grupo de conexiones)
  • Al guardar valores (estado) entre llamadas, debe tener mucho cuidado. Nunca almacene valores en sus propias cachés o miembros estáticos; esto no es seguro en clústeres y otras condiciones extrañas, y el servidor de aplicaciones puede hacer cosas terribles con sus datos. En su lugar, utilice beans con estado o una base de datos.
  • En particular, nunca guarde objetos JDBC (Connections, ResultSets, PreparedStatements, etc.) sobre diferentes invocaciones remotas; deje que el servidor de aplicaciones lo administre. El servidor de aplicaciones no solo proporciona un grupo de conexiones, sino que también almacena en caché sus PreparedStatements.

Eliminando fugas

Hay varios procesos y herramientas disponibles para ayudar a detectar y eliminar fugas de JDBC:

  1. Durante el desarrollo, la detección temprana de errores es, con mucho, el mejor enfoque:

    1. Prácticas de desarrollo: las buenas prácticas de desarrollo deberían reducir la cantidad de errores en su software antes de que salga del escritorio del desarrollador. Las prácticas específicas incluyen:

      1. Programación en pareja , para educar a quienes no tienen suficiente experiencia
      2. Revisiones de código porque muchos ojos son mejores que uno
      3. Prueba unitaria, lo que significa que puede ejercitar toda su base de código desde una herramienta de prueba que hace que la reproducción de fugas sea trivial
      4. Utilice bibliotecas existentes para la agrupación de conexiones en lugar de crear las suyas propias
    2. Análisis de código estático: utilice una herramienta como el excelente Findbugs para realizar un análisis de código estático. Esto detecta muchos lugares donde close () no se ha manejado correctamente. Findbugs tiene un complemento para Eclipse, pero también se ejecuta de forma independiente para casos únicos, tiene integraciones en Jenkins CI y otras herramientas de compilación

  2. En tiempo de ejecución:

    1. Sostenibilidad y compromiso

      1. Si la capacidad de retención del ResultSet es ResultSet.CLOSE_CURSORS_OVER_COMMIT, el ResultSet se cierra cuando se llama al método Connection.commit (). Esto se puede configurar mediante Connection.setHoldability () o mediante el método Connection.createStatement () sobrecargado.
    2. Registro en tiempo de ejecución.

      1. Pon buenas declaraciones de registro en tu código. Estos deben ser claros y comprensibles para que el cliente, el personal de soporte y los compañeros de equipo puedan comprenderlos sin capacitación. Deben ser concisos e incluir la impresión del estado / valores internos de las variables y atributos clave para que pueda rastrear la lógica de procesamiento. Un buen registro es fundamental para depurar aplicaciones, especialmente aquellas que se han implementado.
      2. Puede agregar un controlador JDBC de depuración a su proyecto (para la depuración, no lo implemente). Un ejemplo (no lo he usado) es log4jdbc . Luego, debe hacer un análisis simple en este archivo para ver qué ejecuciones no tienen un cierre correspondiente. El conteo de los abiertos y los cerrados debe resaltar si hay un problema potencial

        1. Seguimiento de la base de datos. Supervise su aplicación en ejecución utilizando herramientas como la función 'Supervisar SQL' de SQL Developer o TOAD de Quest . El monitoreo se describe en este artículo . Durante la supervisión, consulta los cursores abiertos (por ejemplo, de la tabla v $ sesstat) y revisa su SQL. Si el número de cursores aumenta y (lo más importante) se vuelve dominado por una declaración SQL idéntica, sabe que tiene una fuga con ese SQL. Busque su código y revíselo.

Otros pensamientos

¿Puedes usar WeakReferences para manejar conexiones de cierre?

Las referencias débiles y suaves son formas de permitirle hacer referencia a un objeto de una manera que le permita a la JVM recolectar basura al referente en cualquier momento que lo considere adecuado (asumiendo que no hay cadenas de referencia fuertes para ese objeto).

Si pasa una ReferenceQueue en el constructor a la ReferenceQueue suave o débil, el objeto se coloca en ReferenceQueue cuando el objeto es GC'ed cuando ocurre (si ocurre). Con este enfoque, puede interactuar con la finalización del objeto y podría cerrar o finalizar el objeto en ese momento.

Las referencias fantasmas son un poco más extrañas; su propósito es solo controlar la finalización, pero nunca puede obtener una referencia al objeto original, por lo que será difícil llamar al método close () en él.

Sin embargo, rara vez es una buena idea intentar controlar cuándo se ejecuta el GC (las referencias débiles, suaves y fantasma le informan después del hecho de que el objeto está en cola para GC). De hecho, si la cantidad de memoria en la JVM es grande (por ejemplo, -Xmx2000m), es posible que nunca GC el objeto y, de todos modos, experimente el ORA-01000. Si la memoria de la JVM es pequeña en relación con los requisitos de su programa, es posible que los objetos ResultSet y PreparedStatement sean GCed inmediatamente después de la creación (antes de que pueda leer de ellos), lo que probablemente fallará en su programa.

TL; DR: El mecanismo de referencia débil no es una buena manera de administrar y cerrar objetos Statement y ResultSet.

Andrew Alcock
fuente
3
Si crea declaraciones en un ciclo, asegúrese de que esté cerrado en el ciclo; de lo contrario, terminará cerrando solo la última declaración.
basiljames
Gracias, basiljames. Acabo de editar la respuesta para agregar el punto que hizo.
Andrew Alcock
@ Andrew Alcock ¡Muchas gracias! Andrés. ¿Podrías responder también a la sexta?
Kanagavelu Sugumar
@AndrewAlcock Por favor ... por favor ... por favor ... responda también a mi séptima pregunta. Desde nuestro proyecto nos enfrentamos a ORA-01000 con mucha frecuencia durante las pruebas de carga. Tus aportaciones son más valiosas para mí. ¡Muchas gracias de antemano!
Kanagavelu Sugumar
RE: 7: puede probar la búsqueda de proximidad con una herramienta como grep. Cuando reconozca un SQL (seleccionar, insertar, actualizar, eliminar), vea la proximidad de la palabra close () junto a la declaración. Si la proximidad está más lejos de lo esperado, esa podría ser una forma de investigar dónde falta. lightboxtechnologies.com/2012/07/27/…
Dom
28

Estoy agregando algunos más comprensión.

  1. Cursor se trata solo de un objeto de declaración; No es resultSet ni el objeto de conexión.
  2. Pero aún tenemos que cerrar el conjunto de resultados para liberar algo de memoria de Oracle. Aún así, si no cierra el conjunto de resultados, eso no se contará para CURSORES.
  3. El objeto de declaración de cierre también cerrará automáticamente el objeto del conjunto de resultados.
  4. Se creará un cursor para todas las instrucciones SELECT / INSERT / UPDATE / DELETE.
  5. Cada instancia de ORACLE DB se puede identificar mediante Oracle SID; De manera similar, ORACLE DB puede identificar cada conexión mediante el SID de conexión. Ambos SID son diferentes.
  6. Entonces, la sesión de ORACLE no es más que una conexión jdbc (tcp); que no es más que un SID.
  7. Si establecemos el máximo de cursores en 500, entonces es solo para una sesión / conexión / SID de JDBC.
  8. Entonces podemos tener muchas conexiones JDBC con su respectivo número de cursores (declaraciones).
  9. Una vez que se termina la JVM, todas las conexiones / cursores se cerrarán, O se cerrará la conexión JDBCC. Los CURSORES con respecto a esa conexión se cerrarán.

Iniciar sesión como sysdba.

En Putty (inicio de sesión de Oracle):

  [oracle@db01 ~]$ sqlplus / as sysdba

En SqlPlus:

Nombre de usuario: sys as sysdba

Establezca el valor de session_cached_cursors en 0 para que no tenga cursores cerrados.

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

Seleccione el conjunto de valores OPEN_CURSORS existente por conexión en la base de datos

 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;

A continuación se muestra la consulta para encontrar la lista de conexiones / SID con valores de cursor abiertos.

 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'

Utilice la siguiente consulta para identificar los sql en los cursores abiertos

 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'

¡Ahora depure el código y disfrute! :)

Kanagavelu Sugumar
fuente
1
Aquí hay otra consulta que parece funcionar bien: stackoverflow.com/a/2560415/32453
rogerdpack
4

Corrija su código de esta manera:

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()
} 

¿Estás seguro de que realmente estás cerrando tus pStatements, conexiones y resultados?

Para analizar objetos abiertos, puede implementar un patrón de delegador, que envuelve el código alrededor de sus objetos statemant, conexión y resultado. Entonces verá si un objeto se cierra con éxito.

Un ejemplo de: 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");
        }
    }
}
Mirko
fuente
3

Si su aplicación es una aplicación Java EE que se ejecuta en Oracle WebLogic como servidor de aplicaciones, una posible causa de este problema es la configuración de Tamaño de caché de declaración en WebLogic.

Si la configuración de Tamaño de caché de declaración para una fuente de datos en particular es aproximadamente igual o mayor que la configuración de recuento máximo de cursores abiertos de la base de datos de Oracle, entonces todos los cursores abiertos pueden ser consumidos por declaraciones SQL almacenadas en caché que WebLogic mantiene abiertas, lo que resulta en el error ORA-01000.

Para solucionar esto, reduzca la configuración de Tamaño de caché de declaración para cada fuente de datos de WebLogic que apunte a la base de datos de Oracle para que sea significativamente menor que la configuración de recuento máximo de cursor en la base de datos.

En la Consola de administración de WebLogic 10, la configuración de Tamaño de caché de declaración para cada fuente de datos se puede encontrar en Servicios (navegación izquierda)> Fuentes de datos> (fuente de datos individual)> pestaña Grupo de conexiones.

Jon Schneider
fuente
1
Hibernate también tiene un caché de declaración. Véase también developer.jboss.org/wiki/…
Pino
3

Yo también había enfrentado este problema. La siguiente excepción solía venir

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

Estaba usando Spring Framework con Spring JDBC para la capa dao.

Mi aplicación solía filtrar cursores de alguna manera y después de unos minutos más o menos, solía darme esta excepción.

Después de mucha depuración y análisis exhaustivos, descubrí que existía el problema con la indexación, la clave principal y las restricciones únicas en una de las tablas que se usaban en la consulta que estaba ejecutando.

Mi aplicación intentaba actualizar las columnas que se indexaron por error . Entonces, cada vez que mi aplicación accedía a la consulta de actualización en las columnas indexadas, la base de datos intentaba reindexar en función de los valores actualizados. Estaba goteando los cursores .

Pude resolver el problema haciendo una indexación adecuada en las columnas que se usaron para buscar en la consulta y aplicando las restricciones apropiadas donde sea necesario.

Piyush Verma
fuente
2

Hoy me enfrenté al mismo problema (ORA-01000). Tuve un bucle for en el try {}, para ejecutar una instrucción SELECT en una base de datos de Oracle muchas veces, (cada vez que cambiaba un parámetro), y finalmente {} tenía mi código para cerrar Resultset, PreparedStatement y Connection como de costumbre . Pero tan pronto como llegué a una cantidad específica de bucles (1000) recibí el error de Oracle sobre demasiados cursores abiertos.

Basado en la publicación de Andrew Alcock anterior, hice cambios para que dentro del ciclo, cerrara cada conjunto de resultados y cada declaración después de obtener los datos y antes de volver a realizar el ciclo, y eso resolvió el problema.

Además, exactamente el mismo problema ocurrió en otro ciclo de declaraciones de inserción, en otra base de datos de Oracle (ORA-01000), esta vez después de 300 declaraciones. Nuevamente, se resolvió de la misma manera, por lo que el PreparedStatement o el ResultSet o ambos, cuentan como cursores abiertos hasta que se cierran.

Kinnison84
fuente
Esto no parece correcto. Spring documenta que es responsable de cerrar ResultSets ( docs.spring.io/spring/docs/current/spring-framework-reference/… ).
Ryan
solo para aclarar, en esos ejemplos no estaba usando Spring.
Kinnison84
1

¿Estableció autocommit = true? Si no, intente esto:

{ //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 
paweloque
fuente
¿Podría responder también a las otras preguntas?
Kanagavelu Sugumar
2
Autocommit no cierra las conexiones, solo confirma automáticamente cada declaración inmediatamente después de la ejecución. Si utiliza la confirmación automática, no obtiene valor de una de las propiedades más importantes de la base de datos: las transacciones. En su lugar, podría considerar usar una base de datos NoSQL.
Andrew Alcock
1

consulta para encontrar sql que se abrió.

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
Hlex
fuente
1

Este problema ocurre principalmente cuando está utilizando la agrupación de conexiones porque cuando cierra la conexión, esa conexión vuelve al grupo de conexiones y todos los cursores asociados con esa conexión nunca se cierran ya que la conexión a la base de datos aún está abierta. Entonces, una alternativa es disminuir el tiempo de conexión inactiva de las conexiones en el grupo, por lo que cada vez que la conexión permanece inactiva en la conexión durante, digamos, 10 segundos, la conexión a la base de datos se cerrará y se creará una nueva conexión para poner en el grupo.

Raveesh Badoni
fuente
0

En nuestro caso, estábamos usando Hibernate y teníamos muchas variables que hacían referencia a la misma entidad mapeada de Hibernate. Estábamos creando y guardando estas referencias en un bucle. Cada referencia abrió un cursor y lo mantuvo abierto.

Descubrimos esto usando una consulta para verificar la cantidad de cursores abiertos mientras ejecutamos nuestro código, avanzando con un depurador y comentando cosas de manera selectiva.

En cuanto a por qué cada nueva referencia abrió otro cursor: la entidad en cuestión tenía colecciones de otras entidades asignadas y creo que esto tuvo algo que ver con eso (quizás no solo esto solo, sino en combinación con cómo habíamos configurado el modo de búsqueda y configuración de caché). La propia Hibernate ha tenido errores por no cerrar los cursores abiertos, aunque parece que se han solucionado en versiones posteriores.

Dado que de todos modos no necesitábamos tener tantas referencias duplicadas a la misma entidad, la solución fue dejar de crear y mantener todas esas referencias redundantes. Una vez que hicimos eso, el problema cuando estábamos fuera.

dshiga
fuente
0

Tuve este problema con mi fuente de datos en WildFly y Tomcat, conectándome a un Oracle 10g.

Descubrí que, bajo ciertas condiciones, la declaración no se cerraba incluso cuando se invocaba statement.close (). El problema fue con el controlador de Oracle que estábamos usando: ojdbc7.jar. Este controlador está diseñado para Oracle 12c y 11g, y parece que tiene algunos problemas cuando se usa con Oracle 10g, así que bajé a ojdbc5.jar y ahora todo está funcionando bien.

Gilbertoag
fuente
0

Enfrenté el mismo problema porque estaba consultando db durante más de 1000 iteraciones. He usado try y finalmente en mi código. Pero seguía recibiendo un error.

Para resolver esto, inicié sesión en Oracle DB y ejecuté la siguiente consulta:

ALTER SYSTEM SET open_cursors = 8000 SCOPE = BOTH;

Y esto resolvió mi problema de inmediato.

RArora
fuente
Esto alivió algunos síntomas, pero en realidad no resolvió el problema. Necesita arreglar su código para que cierre los cursores una vez que haya terminado con ellos.
APC