2009-09-17 55 views
6

Estamos utilizando Spring SimpleJdbcCall para llamar a procedimientos almacenados en Oracle que devuelven los cursores. Parece que SimpleJdbcCall no está cerrando los cursores y después de un tiempo se excede el máximo de los cursores abiertos.ORA-01000: se han excedido los cursores máximos cuando se utiliza Spring SimpleJDBCCall

ORA-01000: maximum open cursors exceeded ; nested exception is java.sql.SQLException: ORA-01000: maximum open cursors exceeded spring 

Hay algunas otras personas en foros que han experimentado esto, pero al parecer no hay respuestas. Me parece un error en el soporte de Spring/Oracle.

Este error es crítico y podría afectar nuestro uso futuro de Spring JDBC.

¿Alguien ha encontrado una solución, ya sea rastreando el problema hasta el código de Spring o encontró una solución que evita el problema?

Estamos utilizando Spring 2.5.6.

Aquí es la nueva versión del código utilizando SimpleJdbcCall que parece no estar cerrando correctamente el conjunto de resultados que los proc retornos a través de un cursor:

... 
SimpleJdbcCall call = new SimpleJdbcCall(dataSource); 

Map params = new HashMap(); 
params.put("remote_user", session.getAttribute("cas_username")); 

Map result = call 
    .withSchemaName("urs") 
    .withCatalogName("ursWeb") 
    .withProcedureName("get_roles") 
    .returningResultSet("rolesCur", new au.edu.une.common.util.ParameterizedMapRowMapper()) 
    .execute(params); 
List roles = (List)result.get("rolesCur") 

La versión anterior del código que no utiliza primavera JDBC no tiene este problema:

oracleConnection = dataSource.getConnection(); 
callable = oracleConnection.prepareCall(
     "{ call urs.ursweb.get_roles(?, ?) }" ); 
callable.setString(1, (String)session.getAttribute("cas_username")); 
callable.registerOutParameter (2, oracle.jdbc.OracleTypes.CURSOR); 
callable.execute(); 
ResultSet rset = (ResultSet)callable.getObject(2); 
... do stuff with the result set 
if (rset != null) rset.close(); // Explicitly close the resultset 
if (callable != null) callable.close(); //Close the callable 
if (oracleConnection != null) oracleConnection.close(); //Close the connection 

Al parecer, la primavera JDBC no está llamando rset.close(). Si hago un comentario sobre esa línea en el código anterior, luego de la prueba de carga obtenemos la misma excepción de base de datos.

+3

Por favor, publique un código que muestre cómo está utilizando SimpleJdbcCall. Es muy poco probable que se trate de un error en Spring, y más probablemente de la forma en que lo está utilizando, especialmente si se tiene en cuenta la forma no estándar en que Oracle maneja los resultados. – skaffman

+1

+1 con skaffman. Si no puede encontrar el problema, intente construir un caso de prueba sólido antes de informar un error en http://jira.springframework.org/ –

Respuesta

7

Después de muchas pruebas, hemos resuelto este problema. Es una combinación de cómo estábamos usando el marco de trabajo de primavera y el cliente de Oracle y Oracle DB.Estábamos creando nuevas SimpleJDBCCalls que usaban las llamadas de metadatos del cliente Oracle JDBC que se devolvían como cursores que no se cerraban ni se limpiaban. Considero que esto es un error en el marco Spring JDBC en cómo llama a los metadatos, pero luego no cierra el cursor. Spring debe copiar los metadatos del cursor y cerrarlos correctamente. No me he molestado en abrir un problema de jira con la primavera porque si utilizas las mejores prácticas, el error no se exhibe.

Alterar OPEN_CURSORS o cualquiera de los otros parámetros es la forma incorrecta de solucionar este problema y simplemente retrasa su aparición.

Hemos trabajado alrededor/lo hemos arreglado moviendo el SimpleJDBCCall en un DAO singleton por lo que solo hay un cursor abierto para cada proceso de Oracle que llamemos. Estos cursores están abiertos durante toda la vida de la aplicación, lo que considero un error. Siempre que OPEN_CURSORS sea más grande que el número de objetos SimpleJDBCCall, no habrá problemas.

+5

Espero que haya informado esto si lo considera un error :) –

1

Puedo prometerle que no es primavera. Trabajé en una aplicación Spring 1.x que se lanzó en 2005 y no ha filtrado una conexión desde entonces. (WebLogic 9., JDK 5). No está cerrando sus recursos correctamente.

¿Estás utilizando un grupo de conexiones? ¿Qué servidor de aplicaciones está implementando? ¿Qué versión de Spring? ¿Oráculo? ¿Java? Detalles, por favor.

-3

La solución no está en la primavera, pero en Oracle: es necesario configurar el parámetro de inicialización OPEN_CURSORS a un valor más alto que el valor por defecto 50.

Oracle - al menos como de 8i, tal vez ha cambiado - - Reconstruiría los objetos JDBC PreparedStatement a menos que los dejara abiertos. Esto fue costoso y la mayoría de las personas termina manteniendo un grupo fijo de declaraciones abiertas que se vuelven a enviar.

(echar un vistazo rápido a los documentos 10i, que de forma explícita en cuenta que el controlador de la OCI en caché PreparedStatements, así que estoy asumiendo que el controlador nativo todavía les recrea cada vez)

+2

Esto es una fuga de recursos, la solución a una fuga de recursos es detener goteando, no agregue más agua. –

+1

@Andrew - gracias por comentar junto con su voto negativo. Sin embargo, después de haber trabajado con Oracle desde principios de la década de 1990, resisto mi respuesta. Fuera de la caja, su configuración no es adecuada para una aplicación compleja. Además, el OP está utilizando Spring, que es muy bueno para limpiarlo. Todavía es posible que el OP haya escrito una fuga de recursos en alguna parte, pero es mucho menos probable que si estuviera haciendo una gestión de conexión explícita. – kdgregory

+0

Al volver a leer todas las publicaciones, veo que el OP publicó la respuesta aceptada dos meses después de mi respuesta, lo que indica que en realidad fue una pérdida de recursos con Spring. Sin embargo, dado que la supuesta filtración fue cuando Spring intentó caché de los metadatos, me referiré a mi segundo párrafo, y sigo de pie con esta respuesta. – kdgregory

-2

Oracle OPEN_CURSORS es el bien fundamental . Tenemos una pequeña aplicación 24x7 ejecutándose contra Oracle XE con solo unos pocos cursores aparentemente abiertos. Tuvimos errores intermitentes de los cursores abiertos máximos hasta que establecimos el valor de inicialización de OPEN_CURSORS en> 300

+4

Esta es una fuga de recursos, la solución a una fuga de recursos es dejar de filtrar, no agregar más agua. –

2

Simplemente tenga cuidado al configurar OPEN_CURSORS a valores cada vez más altos ya que hay gastos generales y podría ser un obstáculo para un problema/error real en tu codigo.

no tengo experiencia con el lado del muelle de esto, pero trabajé en una aplicación donde tuvimos muchos problemas con ORA-01000 errores y ajustando constantemente OPEN_CURSORS acaba de hacer desaparecer el problema por un tiempo ...

3

Bueno, tengo este problema cuando estaba leyendo BLOB. La causa principal fue que también estaba actualizando la tabla y el enunciado que contenía la cláusula de actualización no se cerró automáticamente. El cursorleak desagradable come todos los cursores libres. Después de la llamada explícita de statement.close() el error desaparece.

Moral - siempre cerca todo lo, no se basan en una estrecha automática después de desechar Declaración.

Cuestiones relacionadas