JAVA - JDBC - ORACLE - CURSOR

Java - JDBC - ORACLE - CURSOR
INTRODUCCIÓN
Cuando se programa con bases de datos Oracle, una de los problemas que debemos resolver es la lectura de un cursor que lo retorna un procedimiento como un parámetro de salida.
En este artículo veremos como resolver este problema utilizando Java - JDBC, especificamente, utilizaremos el objeto CallableStatement.
La base de datos a utilizar es EUREKA, que la puede descargar desde:
http://gcoronelc.blogspot.com/2011/08/base-de-datos-ejemplo.html
PROCEDIMIENTO ALMACENADO
CREACIÓN
Para ilustrar la demostración utilizaremos un procedimiento almacenado para consultar los movimientos de una cuenta:
create or replace procedure usp_egcc_movimientos
( p_cuenta IN cuenta.chr_cuencodigo%TYPE, 
  p_cursor OUT NOCOPY SYS_REFCURSOR )
as begin
  open p_cursor for 
    select 
      m.chr_cuencodigo cuenta,
      m.int_movinumero nromov,
      m.dtt_movifecha fecha,
      m.chr_tipocodigo tipo,
      t.vch_tipodescripcion descripcion,
      t.vch_tipoaccion accion,
      m.dec_moviimporte importe
    from tipomovimiento t
    join movimiento m 
    on t.chr_tipocodigo = m.chr_tipocodigo
    where m.chr_cuencodigo = p_cuenta;
end;
/
PRUEBA
Para probar el procedimiento almacenado utilizaremos el siguiente script:
declare
  v_cursor SYS_REFCURSOR;
  v_cuenta movimiento.chr_cuencodigo%TYPE;
  v_nromov movimiento.int_movinumero%TYPE;
  v_fecha movimiento.dtt_movifecha%TYPE;
  v_tipo tipomovimiento.chr_tipocodigo%TYPE;
  v_desc tipomovimiento.vch_tipodescripcion%TYPE;
  v_accion tipomovimiento.vch_tipoaccion%TYPE;
  v_importe movimiento.dec_moviimporte%TYPE;
begin
  usp_egcc_movimientos( '00100001', v_cursor );
  loop
    fetch v_cursor into v_cuenta, v_nromov, v_fecha, 
      v_tipo, v_desc, v_accion, v_importe;
    exit when v_cursor%NOTFOUND;
    dbms_output.put_line(v_cuenta || ' | ' || v_nromov
      || ' | ' || v_fecha || ' | ' || v_tipo || ' | ' || 
      v_desc || ' | ' || v_accion || ' | ' || v_importe);
  end loop;
  close v_cursor;
end;
/
No olvidar que debe habilitar la salida:
set serveroutput on
El resultado que se obtiene es similar a los siguiente:
00100001 | 1 | 06/01/08 | 001 | Apertura de Cuenta | INGRESO | 2800
00100001 | 7 | 15/03/08 | 003 | Deposito | INGRESO | 1000
00100001 | 4 | 14/02/08 | 003 | Deposito | INGRESO | 2000
00100001 | 2 | 15/01/08 | 003 | Deposito | INGRESO | 3200
00100001 | 6 | 03/03/08 | 004 | Retiro | SALIDA | 800
00100001 | 5 | 25/02/08 | 004 | Retiro | SALIDA | 500
00100001 | 3 | 20/01/08 | 004 | Retiro | SALIDA | 800
CODIFICACIÓN EN JAVA
FUNDAMENTOS
Se utilizará un objeto de tipo CallableStatement, que permite declarar un procedimiento almacenado y registrar parámetros de salida de tipo Cursor.
String sql = "{call usp_egcc_movimientos(?,?)}";
CallableStatement cstm = cn.prepareCall(sql);
cstm.setString(1, "00100001"); 
cstm.registerOutParameter(2, OracleTypes.CURSOR);
Después de ejecutar el procedimiento debemos obtener el cursor en un objeto de tipo ResultSet.
cstm.executeUpdate();
ResultSet rs = (ResultSet) cstm.getObject(2);
CLASE COMPLETA
A continuación tenemos la clase completa:
package pe.egcc.app;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import oracle.jdbc.OracleTypes;

/**
 *
 * @author Eric Gustavo Coronel Castillo
 * @blog gcoronelc.blogspot.com
 * @fecha 20/05/2014
 * @clase DemoCursor
 * @descripcion: Esta clase sirve para leer un cursor Oracle
 */
public class DemoCursor {

  public static void main(String[] args) {
    Connection cn = null;
    try {
      // Parámetros de conexión
      String driver = "oracle.jdbc.OracleDriver";
      String url = "jdbc:oracle:thin:@localhost:1521:XE";
      String user = "eureka";
      String pwd = "admin";
      // Conexión
      Class.forName(driver).newInstance();
      cn = DriverManager.getConnection(url, user, pwd);
      // Proceso
      String sql = "{call usp_egcc_movimientos(?,?)}";
      CallableStatement cstm = cn.prepareCall(sql);
      cstm.setString(1, "00100001"); 
      cstm.registerOutParameter(2, OracleTypes.CURSOR);
      cstm.executeUpdate();
      ResultSet rs = (ResultSet) cstm.getObject(2);
      while(rs.next()){
        String texto = rs.getString("cuenta");
        texto += " | " + rs.getString("nromov");
        texto += " | " + rs.getString("fecha");
        texto += " | " + rs.getString("tipo");
        texto += " | " + rs.getString("descripcion");
        texto += " | " + rs.getString("accion");
        texto += " | " + rs.getString("importe");
        System.out.println(texto);
      }
      rs.close();
      cstm.close();
    } catch (Exception e) {
      e.printStackTrace();
    } finally{
      try {
        cn.close();
      } catch (Exception e) {
      }
    }
  }
}
El resultado que se obtiene es el siguiente:
run:
00100001 | 1 | 2008-01-06 00:00:00.0 | 001 | Apertura de Cuenta | INGRESO | 2800
00100001 | 7 | 2008-03-15 00:00:00.0 | 003 | Deposito | INGRESO | 1000
00100001 | 4 | 2008-02-14 00:00:00.0 | 003 | Deposito | INGRESO | 2000
00100001 | 2 | 2008-01-15 00:00:00.0 | 003 | Deposito | INGRESO | 3200
00100001 | 6 | 2008-03-03 00:00:00.0 | 004 | Retiro | SALIDA | 800
00100001 | 5 | 2008-02-25 00:00:00.0 | 004 | Retiro | SALIDA | 500
00100001 | 3 | 2008-01-20 00:00:00.0 | 004 | Retiro | SALIDA | 800
BUILD SUCCESSFUL (total time: 1 second)
Espero que este artículo le sea útil.
CÓDIGO FUENTE: EUREKA-CS-ORACLE-JDBC
En esta sección te presento un video que una aplicación CLIENTE-SERVIDOR desarrollada con Java y Oracle.
Tú tienes acceso al código fuente de esta aplicación, después del video tienes el enlace.