Error ORA-01000: Problema de punteros al hacer los INSERT con Java mediante JDBC


ERROR: ORA-01000: maximum open cursors exceeded

CAUSA: Un lenguaje host ha intentado abrir demasiados cursores. El parámetro de Base de Datos que determina el numero de cursores por usuario es OPEN_CURSORS.

SOLUCIÓN: Podemos cambiar este parámetro en Base de Datos, previamente parando la BBDD y reiniciándola después.

¿Qué es un cursor?
Pregunta interesante para los que no somos expertos en Base de Datos. Un cursor es un recurso mediante el cuál, la base de datos mantiene el estado de una consulta, específicamente, la posición donde está el lector en un ResultSet. Cada sentencia SELECT tiene un cursor, y un procedimiento PL/SQL puede abrir tantos cursores como se requieran. Ver Orafaq.

Una instancia de base de datos sirve normalmente diferentes esquemas, muchos usuarios con múltiples sesiones. Para hacer esto, se fija un número de cursores disponibles para todos los esquemas, usuarios y sesiones. Cuando todos estan abiertos (en uso) y se pide un nuevo cursor, la petición falla con un error ORA-01000.

¿Se puede solucionar mediante el código en lugar de modificar el parámetro de BBDD?
En el caso que nos ocupa, el problema sobrevino al intentar hacer las sentencias INSERT con un PreparedStatement.

En lugar de ello, si utilizamos un Statement que realizase la misma tarea exactamente, nuestro problema desapareció. ¿Por qué?, esto nos lleva a la siguiente pregunta…

¿Cuál es la diferencia entre Statement y PreparedStatement?
Aquí tenemos la respuesta. Básicamente, PreparedStatement es una buena práctica por ser una sentencia precompilada, esto es, cuando ejecutamos una consulta SQL, el servidor de BBDD preparará un execution plan antes de que se ejecute la consulta, dicho plan es cacheado en el servidor de BBDD para futuras ejecuciones.

Por tanto, PreparedStatment es:
– Al ser el execution plan cacheado, el rendimiento es mejor.
– Es una buena forma contra ataques de SQL Injection, ya que escapa los caracteres de entrada.
– Como es una Statement con variables no ligadas, la BBDD es libre de optimizar al máximo. Las consultas individuales irán más rápido, pero la desventaja es que necesitas la compilación en BBDD todo el tiempo, lo cual es peor que el beneficio de una query rápida.

Resumen
Con estos datos, quizás el problema se solucionó debido a que al ser Statement más lento, le daba tiempo a limpiar/cerrar las conexiones o cursores y por ello el problema desapareció.

Si alguien tiene más idea que yo de esto, o se ha enfrentado al mismo problema, me gustaría que me explicase un poco más el por qué de este asunto por privado.