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.
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.
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);
Como se ha indicado, los objetos CallableStatement pueden tomar tres tipos de parámetros:
Los parámetros IN se manejan de la misma forma que PreparedStatements. Los diversos métodos set de la clase PreparedStatement heredada se utilizan para establecer los parámetros.
Los parámetros OUT se manejan con el método registerOutParameter. En la forma más común de registerOutParameter, el primer parámetro es un índice de parámetro y el segundo es un tipo de SQL. Este indica al controlador JDBC qué tipo de datos debe esperar del parámetro cuando se procesa la sentencia. Existen otras dos variantes del método registerOutParameter que pueden encontrarse en el Javadoc del paquete java.sql.
Los parámetros INOUT requieren que se realice el trabajo tanto para parámetros IN como para parámetros OUT. Para cada parámetro INOUT, debe llamarse a un método set y al método registerOutParameter para que pueda procesarse la sentencia. Si alguno de los parámetros no se establece o registra, se lanza una SQLException cuando se procesa la sentencia.
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.
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
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.