2010-01-28 31 views
15

Estoy utilizando las clases JdbcTemplate y StoredProcedure de Spring. Tengo problemas para que la clase de procedimiento almacenado funcione para mí.Procedimiento almacenado de Spring: los resultados que vuelven del procedimiento siempre están vacíos

Tengo un procedimiento almacenado en una base de datos de Oracle. Su firma es

CREATE OR REPLACE PROCEDURE PRC_GET_USERS_BY_SECTION 
(user_cursor OUT Pkg_Types.cursor_type 
, section_option_in IN Varchar2 
, section_in IN Varchar2) AS .... 

donde

TYPE cursor_type IS REF CURSOR; 

tengo a crear la siguiente clase de procedimiento almacenado para obtener información del procedimiento de Oracle

private class MyStoredProcedure extends StoredProcedure 
{ 
    public MyStoredProcedure(JdbcTemplate argJdbcTemplate) 
    { 
     super(argJdbcTemplate, "PRC_GET_USERS_BY_SECTION"); 
     declareParameter(new SqlOutParameter("output", OracleTypes.CURSOR)); 
     declareParameter(new SqlParameter("input1", Types.VARCHAR)); 
     declareParameter(new SqlParameter("input2", Types.VARCHAR)); 
     compile();   
    } 


    public Map<String, Object> execute() { 

     Map<String, Object> inParams = new HashMap<String, Object>(); 
     inParams.put("input1", "BG"); 
     inParams.put("input2", "FE"); 
     Map output = execute(inParams); 
     return output; 
    } 
} 

Estoy llamando a esto en un método en una de mis clases DAO

public List<String> getUserListFromProcedure() throws BatchManagerException 
{ 
    MyStoredProcedure sp = new MyStoredProcedure(this.jdbcTemplate); 
    Map<String, Object> result = new HashMap<String, Object>(); 
    try 
    { 
     result = sp.execute(); 
    } 

    catch(DataAccessException dae) 
    { 

    } 
    System.out.println(result.size()); 
    return null; 
} 

Sin embargo, el tamaño del mapa siempre es 0, por lo que no se produce ningún problema. Sé que hay filas en la base de datos que coinciden con mis criterios de entrada. También tuve código de trabajo que usaba java.sql.CallableStatement para interactuar con el proceso almacenado de Oracle, por lo que el proceso es bueno. ¿Es incorrecto mezclar OraceleTypes.CURSOR con Spring's Stored Procedure? ¿Qué más puedo usar? También probé SqlReturnResultSet y eso tampoco funcionó.

Respuesta

7

El problema aquí es que la forma en que Oracle hace los procedimientos almacenados no es compatible con JDBC. Los SP de Oracle devuelven los datos del conjunto de resultados a través de los parámetros OUT o los valores de retorno que son cursores, y deben manejarse de manera especial. Esto significa que no puede usar ninguna de las cosas JDBC de Spring que asume el cumplimiento con JDBC, tiene que hacerlo usted mismo.

En la práctica, esto significa que tiene que usar JdbcTemplate y CallableStatementCallback, lo que significa mucha más codificación JDBC manual de lo que idealmente desea, pero todavía tengo que encontrar una manera de evitar esto.

Por un lado, sospecho que la especificación de JDBC se escribió para ajustarse estrechamente a la forma de hacer Sybase (y, por asociación, SQL Server), porque la forma en que se manejan los procedimientos almacenados en JDBC es notable. buen ajuste para esos sistemas (y un mal ajuste para Oracle).

+7

Hola, gracias por su comentario. Lo tengo trabajando con mi procedimiento almacenado de Oracle. El problema fue con el parámetro de salida que había declarado. Los siguientes trabajos declareParameter (new SqlOutParameter ("output", oracle.jdbc.OracleTypes.CURSOR, new RowMapper() {public String mapRow (ResultSet argResults, int argRowNum) arroja SQLException {return argResults.getString (1);}})); Esto está funcionando para mí ahora. Gracias – aos

+2

Debería haber respondido su propia pregunta y haberla seleccionado como la respuesta aceptada. Gracias por publicar de todos modos. –

4

El problema es simple si no pasa un RowMapper mientras declara el outparam que es un CURSOR. Spring va a devolver {} I.e cursor vacío.

declareParameter(new SqlOutParameter("output", OracleTypes.CURSOR)); - returns empty {} 
declareParameter(new SqlOutParameter("output", OracleTypes.CURSOR, new ApplicationMapper()); - returns result 

Donde ApplicationMapper es mi mapeador personalizado que implementa RowMapper.

Cuestiones relacionadas