Recibo una excepción SQL ORA-01000. Entonces tengo algunas consultas relacionadas.
- ¿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)
- ¿Hay alguna forma de configurar el número de objetos de declaración / conjunto de resultados en la base de datos (como conexiones)?
- ¿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?
¿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
¿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
for (String language : additionalLangs) {
SYS.V$OPEN_CURSOR
vista. Esto le dará no solo el SID, sino también el texto SQL.Respuestas:
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:
Error de configuración
Solución:
Fuga del cursor
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:
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 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:
Tenga en cuenta cómo la cláusula finalmente ignora cualquier excepción generada por close ():
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:
Sin embargo, hay una excepción: si está utilizando EJB, o un contenedor Servlet / JSP, debe seguir un modelo de subprocesamiento estricto:
Eliminando fugas
Hay varios procesos y herramientas disponibles para ayudar a detectar y eliminar fugas de JDBC:
Durante el desarrollo, la detección temprana de errores es, con mucho, el mejor enfoque:
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:
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
En tiempo de ejecución:
Sostenibilidad y compromiso
Registro en tiempo de ejecución.
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
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.
fuente
Estoy agregando algunos más comprensión.
Iniciar sesión como sysdba.
En Putty (inicio de sesión de Oracle):
En SqlPlus:
Nombre de usuario:
sys as sysdba
Establezca el valor de session_cached_cursors en 0 para que no tenga cursores cerrados.
Seleccione el conjunto de valores OPEN_CURSORS existente por conexión en la base de datos
A continuación se muestra la consulta para encontrar la lista de conexiones / SID con valores de cursor abiertos.
Utilice la siguiente consulta para identificar los sql en los cursores abiertos
¡Ahora depure el código y disfrute! :)
fuente
Corrija su código de esta manera:
¿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);
fuente
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.
fuente
Yo también había enfrentado este problema. La siguiente excepción solía venir
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.
fuente
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.
fuente
¿Estableció autocommit = true? Si no, intente esto:
fuente
consulta para encontrar sql que se abrió.
fuente
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.
fuente
El uso de procesamiento por lotes resultará en menos gastos generales. Consulte el siguiente enlace para ver ejemplos: http://www.tutorialspoint.com/jdbc/jdbc-batch-processing.htm
fuente
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.
fuente
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.
fuente
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.
fuente