Problema Spring JDBC v3.0.

480 views
Skip to first unread message

cesar ricardo guerra arnaiz

unread,
Jul 21, 2011, 6:57:43 PM7/21/11
to Comunidad Spring Peru
Hola como están compañeros, tengo una consulta haber si me pueden ayudar ya que estoy teniendo un problema al momento de 
obtener datos de un Cursor por medio de Spring JDBC 3.0. En el aplicativo se conecta sin problema a ORACLE, ejecuta CRUDs mediante SQL incrustado a modo hardcode y ahora estoy tratando de obtener datos de Cursor que un Procedure me esta respondiendo. Analizando, he probado un Function sin problemas y otro Procedure que me responde OUTs de tipo primitivos como Varchar2 o Int. El ORACLE Procedure lo tengo dentro de un Package y un pedazo de la sintaxis es esta:
   
PROCEDURE SP_GET_NOMBRES_USERS( estadoParam IN VARCHAR2 := NULL, vCursorOut OUT PKG_USUARIO.MyCursor )

(Tengo un DECLARE con el que valido que el Procedure esta funcionando bien).


El problema va, a mi parecer, en si al parsear en Java el Cursor que me esta devolviendo.

Desde JAVA asi estoy declarando los tipos de parámetros de ORACLE, para posteriormente compilarlos:  

     declareParameter( new SqlParameter(       "estadoParam",  OracleTypes.VARCHAR ) ); 
     declareParameter( new SqlOutParameter(  "vCursorOut",     OracleTypes.CURSOR, new UsuarioRowMapper() ) );

El parseo mediante los datos obtenido en el ResultSet lo hago en el UsuarioRowMapper. Estoy seteando solo esos datos del Bean ya que la lista que el Cursor responde
contiene los campos:  COD_USU, NOM_USU, APE_USU de BD. 

public class UsuarioRowMapper implements ParameterizedRowMapper<Usuario>{ 
public Usuario mapRow( ResultSet rs, int rowNum ) throws SQLException {
   
Usuario objUsuario = new Usuario();
objUsuario.setId(               Integer.parseInt( rs.getString( 1 ) ) );
objUsuario.setNombres(    rs.getString( 2  ) );
objUsuario.setApellidos(    rs.getString( 3  ) );    
         return objUsuario;
}
}

El error que estoy obteniendo repetidas veces es este:

org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback; uncategorized SQLException for SQL [{call PKG_USUARIO.SP_GET_NOMBRES_USERS(?, ?)}]; SQL state [null]; error code [17062]; El cursor de referencia no es válido; nested exception is java.sql.SQLException: El cursor de referencia no es válido
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:952)
at org.springframework.jdbc.core.JdbcTemplate.call(JdbcTemplate.java:985)
at org.springframework.jdbc.object.StoredProcedure.execute(StoredProcedure.java:117)
at org.java.spring.dao.imp.ProcedureORACLE_2.execute(ProcedureORACLE_2.java:58)
at org.java.spring.dao.imp.UsuarioDaoImpl.getProcedureORACLE_02(UsuarioDaoImpl.java:109)
at test.TestSpringJDBC_Oracle.testObtenerProcedureORACLE_02(TestSpringJDBC_Oracle.java:115)
at test.TestSpringJDBC_Oracle.main(TestSpringJDBC_Oracle.java:47)


Haber  si me dan un mano con este problema ya que estoy seguro que va por el tema de RowMapper ya que con datos primitivos como Varchar2 y Int no tengo este problema de obtenerlos del Procedure.


Saludos.


Cesar Ricardo Guerra Arnaiz


Jose Luis Manrique Cabana

unread,
Jul 21, 2011, 7:42:50 PM7/21/11
to spring-user...@googlegroups.com
Prueba cambiando el parametro out a un tipo SYS_REFCURSOR en vez del cursor que creaste, anteriormente he trabajado con oracle y usando esa forma de declarar el cursor no he tenido problemas. 

Espero pueda ser de ayuda!

--
Has recibido este mensaje porque estás suscrito al grupo "Spring User Group Peru" de Grupos de Google.
Para publicar una entrada en este grupo, envía un correo electrónico a spring-user...@googlegroups.com.
Para anular tu suscripción a este grupo, envía un correo electrónico a spring-user-group...@googlegroups.com
Para tener acceso a más opciones, visita el grupo en http://groups.google.com/group/spring-user-group-peru?hl=es.



--
Saludos cordiales,
Jose Luis Manrique Cabana


cesar ricardo guerra arnaiz

unread,
Jul 22, 2011, 4:21:29 AM7/22/11
to Comunidad Spring Peru
Hola gracias por responder... analizando tu recomendacion verifique y aplique el cambio, pero igual me salio el mismo error, luego he estado leyendo y me informe que dentro del Procedure no deberia hacerle un Close al CURSOR, sino que ese cierre deberia controlarlo desde JAVA, asi que eso he hecho y ahora me esta saliendo este error
 
org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback; uncategorized SQLException for SQL [{call PKG_USUARIO.SP_GET_NOMBRES_USERS(?, ?)}]; SQL state [72000]; error code [1002]; ORA-01002: recuperación fuera de secuencia
; nested exception is java.sql.SQLException: ORA-01002: recuperación fuera de secuencia


Segun lo que me informe de ORACLE sobre el error ORA-01002 y ese error tiene que ver netamente con el manejo del FETH, pero a mi parecer lo estoy controlando bien ...

 

     PROCEDURE SP_GET_NOMBRES_USERS( estadoParam IN  VARCHAR2 := NULL,
                                                                 vCursorOut  OUT PKG_USUARIO.MyCursor
                                                               )
            AS

            vCOD_USU INTEGER;
            vNOM_USU VARCHAR2( 20 );
            vAPE_USU VARCHAR2( 20 );

            vQUERY VARCHAR2( 800 );

            TYPE CUR_TYPE IS REF CURSOR;
            vCURSOR  CUR_TYPE;

         BEGIN           
            vQUERY := ' SELECT U.COD_USU, U.NOM_USU, U.APE_USU
                        FROM   RGUERRA.TB_USUARIOS U
                        WHERE  U.ESTADO_USU = ''' || estadoParam || ''' ';

            DBMS_OUTPUT.PUT_LINE( '- vQUERY: ' || vQUERY );

            OPEN vCURSOR FOR vQUERY;

              LOOP
                  FETCH vCURSOR
                  INTO  vCOD_USU,
                           vNOM_USU,
                           vAPE_USU;

                   EXIT WHEN vCURSOR%NOTFOUND;

                  --DBMS_OUTPUT.PUT_LINE( '- vCOD_USU: ' || vCOD_USU );
                  --DBMS_OUTPUT.PUT_LINE( '- vNOM_USU: ' || vNOM_USU );
                  --DBMS_OUTPUT.PUT_LINE( '- vAPE_USU: ' || vAPE_USU );
                 
              END LOOP;
             
             --CLOSE vCURSOR;

           vCursorOut := vCURSOR;

        END SP_GET_NOMBRES_USERS;



Date: Thu, 21 Jul 2011 18:42:50 -0500
Subject: Re: [springperu] Problema Spring JDBC v3.0.
From: kensh...@gmail.com
To: spring-user...@googlegroups.com

Jose Luis Manrique Cabana

unread,
Jul 22, 2011, 11:33:16 AM7/22/11
to spring-user...@googlegroups.com
Hola Cesar, no se por que presiento que es el open cursor con su respectivo fetch el que esta generando tu problema, lo más simple es  solo hacer un OPEN ((Aqui va el cursor)) FOR ((((Aqui va el select)))) y listo como el cursor es un parametro out no habría problema, es por eso que te decia que mejor uses el SYS_REFCURSOR.

Para más detalles revisa este enlace:
Los procedures que presenta sirven para hacer un select o update (y por que no con la misma idea un delete).

Exitos con la actividad!

ROGER

unread,
Jul 22, 2011, 12:22:56 PM7/22/11
to spring-user...@googlegroups.com
AQUI  HAY EJEMPLO Y COMO LO LLAMO DESDE JAVA

PRIMERO DEFINO
    TYPE C_CURSOR    IS REF  CURSOR ;
    C_EXITO VARCHAR2(10) := 'SUCCESS';
EN EL CABECERA DE MI PAQUETE CORP_CORRELATIVO_SERIE.
****************************************************



 PROCEDURE CORSPS_LIST_CORRE( C_DATOS OUT C_CURSOR,
                                PCCSB_IND_TAQ_DUL IN  CORT_SERIE_BOLETA.CCSB_IND_TAQ_DUL%TYPE,
                                PCCSB_ESTADO IN CORT_SERIE_BOLETA.CCSB_ESTADO%TYPE
                                        ) IS
 
  BEGIN
   /* ABRO MI CURSOR */
   OPEN C_DATOS FOR

    SELECT
    BOL.CCSB_NUMERO_SERIE,
    BOL.CCSB_CORRE_ACTUAL,
    to_char(BOL.CCSB_PRECIO_PASE,'9999990.00')CCSB_PRECIO_PASE,
    BOL.CCSB_IND_TAQ_DUL,
    BOL.CCSB_DESCRIPCION,
    BOL.CCSB_CORRE_FINAL,
    BOL.CCSB_ESTADO ,             
    to_char(bol.ccsb_fec_reg,'DD/MM/YYYY')ccsb_fec_reg
     FROM cort_serie_boleta bol
    
     WHERE
     CCSB_IND_TAQ_DUL= NVL(PCCSB_IND_TAQ_DUL,CCSB_IND_TAQ_DUL)
     AND BOL.CCSB_ESTADO=NVL(PCCSB_ESTADO,CCSB_ESTADO)
     ORDER BY BOL.CCSB_IND_TAQ_DUL, BOL.CCSB_ESTADO,BOL.CCSB_NUMERO_SERIE;

END CORSPS_LIST_CORRE;
    
   *********************
Y ESTA ES LA LLAMADA DESDE JAVA
 *********************************

 public List<SerieBoletaBean> consultarSerieBol(SerieBoletaBean serieBoletaBean) {
         /*LLAMO A LA FUNCION QUE VA EJECUTAR*/
          SerieBolStoredProcedure proc = new SerieBolStoredProcedure(getDataSource());

        Map results = proc.execute(serieBoletaBean);
        List<SerieBoletaBean> lista = (List) results.get("C_CURSOR");

        return lista;
    }


 private class SerieBolStoredProcedure extends StoredProcedure {

        private static final String PROC_PARAM = "CORP_CORRELATIVO_SERIE.CORSPS_LIST_CORRE"; //NOMBRE DE MI STORE P.

        public SerieBolStoredProcedure(DataSource ds) {
            super(ds, PROC_PARAM);
            
            declareParameter(new SqlOutParameter("C_CURSOR", OracleTypes.CURSOR, new SerieBolRowMapper()));
            declareParameter(new SqlParameter("PCCSB_IND_TAQ_DUL", Types.VARCHAR));
            declareParameter(new SqlParameter("PCCSB_ESTADO", Types.VARCHAR));
          
         
            compile();
        }

        public Map execute(SerieBoletaBean serieBoletaBean) {
           
            Map inputs = new HashMap();
            if(!serieBoletaBean.getTipo().getCodigo().equals("X"))
            inputs.put("PCCSB_IND_TAQ_DUL", serieBoletaBean.getTipo().getCodigo());
            else
            inputs.put("PCCSB_IND_TAQ_DUL","");
            if(!serieBoletaBean.getEstado().getCodigoEst().equals("X"))
            inputs.put("PCCSB_ESTADO",serieBoletaBean.getEstado().getCodigoEst() );
           else
                inputs.put("PCCSB_ESTADO","");
            System.out.println(inputs.toString());
            return super.execute(inputs);
        }
     }
***************
ESPERO QUE TE SIRVA
SALUDOS
2011/7/22 Jose Luis Manrique Cabana <kensh...@gmail.com>



--
ROGER CARRASCO ARANGO    
Analista - Programador
Contactos:
Cel:  992684195          
Email: roger...@gmail.com

cesar ricardo guerra arnaiz

unread,
Jul 22, 2011, 1:52:07 PM7/22/11
to Comunidad Spring Peru

Que tal Roger interesante tu ejemplo ... es casi idéntico a como lo tengo manejado yo, a excepción del PROCEDURE en si que lo tenia con FETCH. Me interesa ver el tu clase:
SerieBolRowMapper... ya que ahí es donde realizas el parseo respectivo, si pudieras enviármela para ojearla.

No se porque ese limitante en si de no usar FETCH en el desarrollo de CURSORES en ORACLE Procedure, para ser obtenido dentro en una lógica JAVA, ya que si por ejemplo sale un requerimiento de consumir Procedure de tipo Regresión (desarrollos antiguos), para obtener algunos datos "y estos tiene internamente una Lógica con Fetch por N motivos", por el simple hecho de que JAVA tiene este problema en la obtención, no se va a mandar modificar dicho Procedure. Que opinan.




Cesar Ricardo Guerra Arnaiz
 



Date: Fri, 22 Jul 2011 11:22:56 -0500

Subject: Re: [springperu] Problema Spring JDBC v3.0.

ROGER

unread,
Jul 22, 2011, 2:16:07 PM7/22/11
to spring-user...@googlegroups.com
HAY TINES CESAR LA CLASE QUE PARSEA

  class SerieBolRowMapper implements RowMapper<SerieBoletaBean> {

        public SerieBoletaBean mapRow(ResultSet rs, int i) throws SQLException {
            SerieBoletaBean bean = new SerieBoletaBean();
            bean.setSerie(rs.getString("CCSB_NUMERO_SERIE"));
            bean.setNumeroInicial(rs.getString("CCSB_CORRE_ACTUAL"));
             bean.setNumeroFinal(rs.getString("CCSB_CORRE_FINAL"));
            bean.setDescripcion(rs.getString("CCSB_DESCRIPCION"));
            bean.setPrecioTex(rs.getString("CCSB_PRECIO_PASE").trim());
            TipoBoletoBean tipo= new TipoBoletoBean();
            tipo.setCodigo(rs.getString("CCSB_IND_TAQ_DUL"));
           
       
            bean.setTipo(tipo);
            EstadoCampoBean ecb= new EstadoCampoBean();
            ecb.setCodigoEst(rs.getString("CCSB_ESTADO"));
           
            bean.setFec_reg(rs.getString("CCSB_FEC_REG"));
           
            return bean;
        }
    }

SALUDOS.

2011/7/22 cesar ricardo guerra arnaiz <cesarricar...@hotmail.com>

cesar ricardo guerra arnaiz

unread,
Jul 22, 2011, 6:25:39 PM7/22/11
to Comunidad Spring Peru

Ok Gracias por los aportes compañeros, al final el problema estaba en si en el ORACLE PROCEDURE, debido al problema con el FETCH del CURSOR, debido a eso modifique en base a las recomendaciones dadas, el diseño del PROCEDURE y con eso ya no pasa el vendito error y muestra los datos de forma correcta. Esto podría tomarse en cuenta como un Workaround, ya que si hubiera tocado no crear el PROCEDURE sino consultar uno que maneja el CURSOR de la otra manera, existirían problemas de nuevo y para modificar un PROCEDURE de Regresión es más bravo debido a las posibles consecuencias.

 

Aquí les comparto trozos de código, de las partes más resaltantes del aplicativo que estaba realizando. Saludos y gracias a todos.

 

  -------------------------------------------------------------------------------------------------

      PROCEDURE SP_GET_NOMBRES_USERS( estadoParam IN  VARCHAR2 := NULL,
                                      vCursorOut  OUT SYS_REFCURSOR /*PKG_USUARIO.MyCursor*/
                                    )
         AS
 
         vQUERY VARCHAR2( 300 );

         BEGIN  
           
           IF( estadoParam IS NOT NULL ) THEN
               vQUERY := ' SELECT U.COD_USU, U.NOM_USU, U.APE_USU
                           FROM   RGUERRA.TB_USUARIOS U
                           WHERE  U.ESTADO_USU = ''' || estadoParam || ''' ';
           ELSE

               vQUERY := ' SELECT U.COD_USU, U.NOM_USU, U.APE_USU
                           FROM   RGUERRA.TB_USUARIOS U ';
           END IF;
               
        OPEN vCursorOut FOR vQUERY; 
 
       
     END SP_GET_NOMBRES_USERS;


    /**
     * getProcedureORACLE_Compuesto
     * @return List<Usuario>
     **/
    public List<Usuario> getProcedureORACLE_Compuesto( String estadoParam ){
             
           List<Usuario> listaDataRetorno = new ArrayList<Usuario>();
          
           try{
               this.getJdbcTemplate().setNativeJdbcExtractor( new SimpleNativeJdbcExtractor() );
              
               ProcedureORACLE_Compuesto objProcedure = new ProcedureORACLE_Compuesto( this.getDataSource() );

               listaDataRetorno = objProcedure.execute( estadoParam ); 
           }
           catch( Exception e ){
                    e.printStackTrace();
           }
       
           return listaDataRetorno;
     }
    

      private static final String STORED_PROCEDURE_NAME = "PKG_USUARIO.SP_GET_NOMBRES_USERS";

      public ProcedureORACLE_Compuesto( DataSource conexion ){
 
          super.setDataSource( conexion );
          super.setSql( STORED_PROCEDURE_NAME );

   
          declareParameter( new SqlParameter(    "estadoParam", OracleTypes.VARCHAR ) );
 
          declareParameter( new SqlOutParameter( "vCursorOut",  OracleTypes.CURSOR, new UsuarioRowMapper() ) );
 
          this.compile();
      }
 
      public List<Usuario> execute( String estadoParam ){
 
          List<Usuario> listaUser = new ArrayList<Usuario>();
         
          Map<String, Object> parametrosIN = new HashMap<String, Object>();
          parametrosIN.put( "estadoParam", estadoParam );
 
          Map<String, Object> parametrosOUT = execute( parametrosIN );
                  
          if( parametrosOUT.isEmpty() ){
              listaUser = null;
          }
          else{
              listaUser = (List<Usuario>)parametrosOUT.get( "vCursorOut" );  //Retorna el CURSOR del HashMap.
          }
         
          return listaUser;

      }

public class UsuarioRowMapper implements ParameterizedRowMapper<Usuario>{
 
    public Usuario mapRow( ResultSet rs, int rowNum ) throws SQLException {
       
        Usuario objUsuario = new Usuario();
       
        objUsuario.setId(              Integer.parseInt( rs.getString( 1 ) ) );
        objUsuario.setNombres(    rs.getString( 2  ) );
        objUsuario.setApellidos(     rs.getString( 3  ) );

        return objUsuario;
    }   
}


TAMANIO [CURSOR PROCEDURE]: 10
- ID:       1
- NOMBRE:   RICARDO
- APELLIDO: GUERRA
- ID:       2
- NOMBRE:   CARLOS
- APELLIDO: VERA
- ID:       3
- NOMBRE:   JONATHAN
- APELLIDO: ROSALES

....
.......

Cesar Ricardo Guerra Arnaiz



Date: Fri, 22 Jul 2011 13:16:07 -0500
Reply all
Reply to author
Forward
0 new messages