Stored Procedures con Spring

De Dos Ideas.
Saltar a: navegación, buscar

Spring Framework brinda una herramienta bastante práctica para invocar a stored procredures o funciones de forma de evitar el manejo de la conexión y facilitar el seteo de los parámetros.

SimpleJdbcCall

Es una clase que provee Spring que representa la llamada a un stored procedure o store function. Se diferencia de cualquier otra clase utilitaria por leer la meta data de la base de datos, permitiendo que solo tengamos que pasarle en la invocación un map con los nombres de los parámetros y sus respectivos valores. No hace falta especificar los tipos de datos. Adicionalmente encapsula el manejo de la conexión y del statement (internamente usa otra clase mas genérica de Spring para JDBC llamada JdbcTemplate).

Como depende de la información que brinda la meta data, que es obtenida por el driver JDBC, las bases soportadas son Derby, MySQL, Microsoft SQL Server, Oracle y DB2.

Ejemplo invocación

public class MiDao {

   private SimpleJdbcCall miStoreProcedureCall;   
       
   public void buscarDireccion(String pametro1, String parametro2) {  
       SqlParameterSource mapIn = new MapSqlParameterSource()
       .addValue("CODIGO_CLIENTE", pametro1)
       .addValue("NUMERO_DOCUMENTO", parametro2);
       
       Map<String, Object> out = getMiStoreProcedureCall().execute(mapIn);
       String direccionCliente = (String) out.get("DIRECCION");
       
       System.out.println("Invocacion exitosa. Direccion cliente: " + direccionCliente);        
   }

}

Configuración

En el ejemplo se decidió por inyectar la clase utilitaria, utilizando configuración en xml. De igual manera se podría haber hecho en el mismo código Java.

La clase SimpleJdbcCall necesita como parámetro del constructor el data source asociado a la base de datos en la cual se encuentra el store procedure.

En el ejemplo, el procedure se encuentra dentro de un package y de ahí una propiedad extra que hay que configurar (sino simplemente obviarla). Arhivo xml:

<beans>
 <bean id="dataSourceApp" class="org.springframework.jndi.JndiObjectFactoryBean" 
       destroy-method="close">
       <property name="jndiName" value="jdbc/miApp"/>
 </bean>
  
 <bean id="jdbc.miStoreP" class="org.springframework.jdbc.core.simple.SimpleJdbcCall">
       <constructor-arg ref="dataSourceApp"/>
       <property name="procedureName" value="BUSCAR_DIRECCION"/>
       <property name="catalogName" value="PACKAGE_CLIENTES"/>
 </bean>
 <bean id="dao.MiDao" class="com.dosideas.MiDao">
       <property name="miStoreProcedureCall" ref="jdbc.miStoreP"/>        
 </bean>    

</beans>

Schema

Como se menciono anteriormente, esta clase se basa en la obtención de la meta data. Para asegurarnos de que la obtenga correctamente debemos saber mas en detalle como la obtiene. Si corremos el ejemplo con un nivel de log en debug vamos a ver lo siguiente:

Retrieving metadata for PACKAGE_CLIENTES/SCHEMA/BUSCAR_DIRECCION

Si el dueño (owner) del package es diferente al del schema al cual nos estamos conectado, no va a poder obtener la meta data, aunque el mismo tenga un sinónimo publico. Lo importante es que Spring no da error en estos casos, sino que continua con la invocación. En nuestro caso seria algo del tipo:

Compiled stored procedure. Call string is [{call PACKAGE_CLIENTES.BUSCAR_DIRECCION()}]

Luego la base de datos nos dara un error indicando que estamos invocando al procedure con una cantidad incorrecta de parametros (ninguno), ocultado el error que origina todo esto.

Para solucionarlo basta con modificar la llamada al execute de SimpleJdbcCall de la siguiente forma:

Map<String, Object> out = getMiStoreProcedureCall().withSchemaName("MI_ESQUEMA")

                                                  .execute(mapIn);