CallableStatements

La interfaz CallableStatement de JDBC amplía PreparedStatement y proporciona soporte para parámetros de salida y de entrada/salida. La interfaz CallableStatement tiene también soporte para parámetros de entrada, que proporciona la interfaz PreparedStatement.

La interfaz CallableStatement permite la utilización de sentencias SQL para llamar a procedimientos almacenados. Los procedimientos almacenados son programas que tienen una interfaz de base de datos. Estos programas tienen lo siguiente:

Conceptualmente, en JDBC una llamada de procedimiento almacenado es una sola llamada a la base de datos, pero el programa asociado con el procedimiento almacenado puede procesar cientos de peticiones de base de datos. El programa de procedimiento almacenado también puede realizar otras diversas tareas programáticas que no realizan habitualmente las sentencias SQL.

Las CallableStatements, debido a que siguen el modelo de PreparedStatement (que consiste en desacoplar las fases de preparación y proceso), permiten la reutilización optimizada (los detalles están en: PreparedStatements). Dado que las sentencias SQL de un procedimiento almacenado están enlazadas a un programa, se procesan como SQL estático, y con ello puede obtenerse un rendimiento superior. La encapsulación de gran cantidad de trabajo de base de datos en una sola llamada de base de datos reutilizable es un ejemplo de utilización óptima de procedimientos almacenados. Solo esta llamada se transmite por la red al otro sistema, pero la petición puede realizar gran cantidad de trabajo en el sistema remoto.

Crear CallableStatements

El método prepareCall se utiliza para crear objetos CallableStatement nuevos. Al igual que en el método prepareStatement, la sentencia SQL debe suministrarse en el momento de crear el objeto CallableStatement. En ese momento, se precompila la sentencia SQL. Por ejemplo, suponiendo que ya exista un objeto Connection denominado conn, el siguiente código crea un objeto CallableStatement y realiza la fase de preparación de la sentencia SQL para que se procese en la base de datos:

PreparedStatement ps = conn.prepareStatement("? = CALL ADDEMPLOYEE(?, ?, ?");

El procedimiento almacenado ADDEMPLOYEE toma parámetros de entrada para un nuevo nombre de empleado, su número de seguridad social y el ID de usuario de su administrador. A partir de esta información, pueden actualizarse varias tablas de base de datos de la empresa con información relativa al empleado, como por ejemplo la fecha en que ha empezado a trabajar, la división, el departamento, etc. Además, un procedimiento almacenado es un programa que puede generar ID de usuario estándar y direcciones de correo electrónico para ese empleado. El procedimiento almacenado también puede enviar un correo electrónico al administrador que ha contratado al empleado con nombres de usuario y contraseñas iniciales; a continuación, el administrador puede proporcionar la información al empleado.

El procedimiento almacenado ADDEMPLOYEE está configurado para tener un valor de retorno. El código de retorno puede ser un código de éxito o error que el programa que efectúa la llamada puede utilizar cuando se produce una anomalía. El valor de retorno también puede definirse como el número de ID de empresa del nuevo empleado. Finalmente, el programa de procedimiento almacenado puede haber procesado consultas internamente y haber dejado los ResultSets de esas consultas abiertos y disponibles para el programa que efectúa la llamada. Consultar toda la información del nuevo empleado y ponerla a disposición del llamador mediante un ResultSet devuelto es una operación que tiene sentido.

En las secciones siguientes se describe cómo realizar cada uno de estos tipos de tareas.

Especificar las características de ResultSet y el soporte de claves generadas automáticamente

Al igual que en createStatement y prepareStatement, existen varias versiones de prepareCall que proporcionan soporte para especificar características de ResultSet. A diferencia de prepareStatement, el método prepareCall no proporciona variantes para trabajar con claves generadas automáticamente a partir de CallableStatements (JDBC 3.0 no soporta este concepto). A continuación se ofrecen algunos ejemplos de llamadas válidas al método prepareCall:

Ejemplo: método prepareCall

// El siguiente código es nuevo en JDBC 2.0

CallableStatement cs2 = conn.prepareCall("? = CALL ADDEMPLOYEE(?, ?, ?)", 
    ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATEABLE);

// Nuevo en JDBC 3.0

CallableStatement cs3 = conn.prepareCall("? = CALL ADDEMPLOYEE(?, ?, ?)",
    ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATEABLE,
    ResultSet.HOLD_CURSOR_OVER_COMMIT);

Manejar los parámetros

Como se ha indicado, los objetos CallableStatement pueden tomar tres tipos de parámetros:

Hallará más información en: Ejemplo: crear un procedimiento con parámetros de entrada y salida.

Al igual que en PreparedStatements, los valores de parámetro de CallableStatement permanecen estables entre los procesos, a menos que llame de nuevo a un método set. El método clearParameters no afecta a los parámetros registrados para la salida. Después de llamar a clearParameters, todos los parámetros IN deben establecerse de nuevo en un valor, pero ninguno de los parámetros OUT tiene que registrarse de nuevo.

Nota: El concepto de parámetro no debe confundirse con el de índice de un marcador de parámetro. Una llamada de procedimiento almacenado espera que se le pase un determinado número de parámetros. Una sentencia SQL determinada contiene caracteres "?" (marcadores de parámetro) para representar los valores que se suministrarán en el momento de la ejecución. El siguiente ejemplo muestra la diferencia que existe entre los dos conceptos:
CallableStatement cs = con.prepareCall("CALL PROC(?, "SECOND", ?)");

cs.setString(1, "First");     //Marcador de parámetro 1, parámetro de procedimiento almacenado 1

cs.setString(2, "Third");     //Marcador de parámetro 2, parámetro de procedimiento almacenado 3

Acceder a los parámetros de procedimientos almacenados por su nombre

Los parámetros de procedimientos almacenados tienen nombres asociados a ellos, como se ve en esta declaración de procedimiento almacenado:

Ejemplo: parámetros de procedimiento almacenado

CREATE
PROCEDURE MYLIBRARY.APROC 
    (IN PARM1 INTEGER) 
LANGUAGE SQL SPECIFIC MYLIBRARY.APROC 
BODY: BEGIN 
    <Realizar aquí una tarea...>
END BODY

Existe un solo parámetro de tipo integer con el nombre PARM1. En JDBC 3.0, existe soporte para especificar parámetros de procedimiento almacenado por el nombre y por índice. El código para configurar una CallableStatement para este procedimiento es el siguiente:

CallableStatement cs = con.prepareCall("CALL APROC(?)");

cs.setString("PARM1", 6);     //Establece el parámetro de entrada del índice 1
                              //(PARM1) en 6.