Acceso a Bases de Datos [JDBC]

Algunas veces es m�s conveniente o eficiente utilizar objetos PreparedStatement para enviar sentencias SQL a la base de datos. Este tipo especial de sentencias se deriva de una clase m�s general, Statement, que ya conocemos.

.�Cu�ndo utilizar un Objeto PreparedStatement

Si queremos ejecutar muchas veces un objeto Statement, reduciremos el tiempo de ejecuci�n si utilizamos un objeto PreparedStatement, en su lugar.

La caracter�sitca principal de un objeto PreparedStatement es que, al contrario que un objeto Statement, se le entrega una sentencia SQL cuando se crea. La ventaja de esto es que en la mayor�a de los casos, esta sentencia SQL se enviar� al controlador de la base de datos inmediatamente, donde ser� compilado. Como resultado, el objeto PreparedStatement no s�lo contiene una sentencia SQL, sino una sentencia SQL que ha sido precompilada. Esto significa que cuando se ejecuta la PreparedStatement, el controlador de base de datos puede ejecutarla sin tener que compilarla primero.

Aunque los objetos PreparedStatement se pueden utilizar con sentencias SQL sin par�metros, probablemente nosotros utilizaremos m�s frecuentemente sentencias con par�metros. La ventajA de utilizar sentencias SQL que utilizan par�metros es que podemos utilizar la misma sentencia y suministrar distintos valores cada vez que la ejecutemos. Veremos un ejemplo de esto en las p�gina siguientes.

.�Crear un Objeto PreparedStatement

Al igual que los objetos Statement, creamos un objeto PreparedStatement con un objeto Connection. Utilizando nuestra conexi�n con abierta en ejemplos anteriores, podr�amos escribir lo siguiente para crear un objeto PreparedStatement que tome dos par�metros de entrada.

PreparedStatement updateSales = con.prepareStatement(
			"UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ?");

La variable updateSales contiene la sentencia SQL, "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ?", que tambi�n ha sido, en la mayor�a de los casos, enviada al controlador de la base de datos, y ha sido precompilado.

.�Suministrar Valores para los Par�metros de un PreparedStatement

Necesitamos suministrar los valores que se utilizar�n en los luegares donde est�n las marcas de interrogaci�n, si hay alguno, antes de ejecutar un objeto PreparedStatement. Podemos hacer esto llamado a uno de los m�todos setXXX definidos en la clase PreparedStatement. Si el valor que queremos sustituir por una marca de interrogaci�n es un int de Java, podemos llamar al m�todo setInt. Si el valor que queremos sustituir es un String de Java, podemos llamar al m�todo setString, etc. En general, hay un m�todo setXXX para cada tipo Java.

Utilizando el objeto updateSales del ejemplo anterior, la siguiente l�nea de c�digo selecciona la primera marca de interrogaci�n para un int de Java, con un valor de 75.

updateSales.setInt(1, 75);

C�mo podr�amos asumir a partir de este ejemplo, el primer argumento de un m�todo setXXX indica la marca de interrogaci�n que queremos seleccionar, y el segundo argumento el valor que queremos ponerle. El siguiente ejemplo selecciona la segunda marca de interrogaci�n con el string "Colombian".

updateSales.setString(2, "Colombian");

Despu�s de que estos valores hayan sido asignados para sus dos par�metros, la sentencia SQL de updateSales ser� equivalente a la sentencia SQL que hay en string updateString que utilizando en el ejemplo anterior. Por lo tanto, los dos fragmentos de c�digo siguientes consiguen la misma cosa.

C�digo 1.

String updateString = "UPDATE COFFEES SET SALES = 75 " + 
		      "WHERE COF_NAME LIKE 'Colombian'";
stmt.executeUpdate(updateString);

C�digo 2.

PreparedStatement updateSales = con.prepareStatement(
	"UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
updateSales.setInt(1, 75); 
updateSales.setString(2, "Colombian"); 
updateSales.executeUpdate().

Utilizamos el m�todo executeUpdate para ejecutar ambas sentencias stmt updateSales. Observa, sin embargo, que no se suministran argumentos a executeUpdate cuando se utiliza para ejecutar updateSales. Esto es cierto porque updateSales ya contiene la sentencia SQL a ejecutar.

Mirando esto ejemplos podr�amos preguntarnos por qu� utilizar un objeto PreparedStatement con par�metros en vez de una simple sentencia, ya que la sentencia simple implica menos pasos. Si actualiz�ramos la columna SALES s�lo una o dos veces, no ser�a necesario utilizar una sentencia SQL con par�metros. Si por otro lado, tuvieramos que actualizarla frecuentemente, podr�a ser m�s f�cil utilizar un objeto PreparedStatement, especialmente en situaciones cuando la utilizamos con un bucle while para seleccionar un par�metro a una sucesi�n de valores. Veremos este ejemplo m�s adelante en esta secci�n.

Una vez que a un par�metro se ha asignado un valor, el valor permanece hasta que lo resetee otro valor o se llame al m�todo clearParameters. Utilizando el objeto PreparedStatement: updateSales, el siguiente fragmento de c�digo reutiliza una sentencia prepared despu�s de resetar el valor de uno de sus par�metros, dejando el otro igual.

updateSales.setInt(1, 100); 
updateSales.setString(2, "French_Roast"); 
updateSales.executeUpdate(); 
// changes SALES column of French Roast row to 100
updateSales.setString(2, "Espresso");
updateSales.executeUpdate(); 
// changes SALES column of Espresso row to 100 (the first 
// parameter stayed 100, and the second parameter was reset
// to "Espresso")

.�Utilizar una Bucle para asignar Valores

Normalmente se codifica m�s sencillo utilizando un bucle for o while para asignar valores de los par�metros de entrada.

El siguiente fragmento de c�digo demuestra la utilizaci�n de un bucle for para asignar los par�metros en un objeto PreparedStatement: updateSales. El array salesForWeek contiene las cantidades vendidas semanalmente. Estas cantidades corresponden con los nombres de los caf�s listados en el array coffees, por eso la primera cantidad de salesForWeek (175) se aplica al primer nombre de caf� de coffees ("Colombian"), la segunda cantidad de salesForWeek (150) se aplica al segundo nombre de caf� en coffees ("French_Roast"), etc. Este fragmento de c�digo demuestra la actualizaci�n de la columna SALES para todos los caf�s de la tabla COFFEES

PreparedStatement updateSales;
String updateString = "update COFFEES " +
		      "set SALES = ? where COF_NAME like ?";
updateSales = con.prepareStatement(updateString);int [] salesForWeek = {175, 150, 60, 155, 90};
String [] coffees = {"Colombian", "French_Roast", "Espresso",
		     "Colombian_Decaf", "French_Roast_Decaf"};
int len = coffees.length;
for(int i = 0; i < len; i++) {
		updateSales.setInt(1, salesForWeek[i]);
		updateSales.setString(2, coffees[i]);
		updateSales.executeUpdate();
	}

Cuando el propietario quiera actualizar las ventas de la semana siguiente, puede utilizar el mismo c�digo como una plantilla. Todo lo que tiene que haces es introducir las nuevas cantidades en el orden apropiado en el array salesForWeek. Los nombres de caf�s del array coffees permanecen constantes, por eso no necesitan cambiarse. (En una aplicaci�n real, los valores probablemente ser�an introducidos por el usuario en vez de desde un array inicializado).

.�Valores de retorno del m�todo executeUpdate

Siempre que executeQuery devuelve un objeto ResultSet que contiene los resultados de una petici�n al controlador de la base datos, el valor devuelto por executeUpdate es un int que indica cu�ntas l�neas de la tabla fueron actualizadas. Por ejemplo, el siguiente c�digo muestra el valor de retorno de executeUpdate asignado a la variable n.

updateSales.setInt(1, 50); 
updateSales.setString(2, "Espresso"); 
int n = updateSales.executeUpdate();
// n = 1 because one row had a change in it

La tabla COFFEES se ha actualziado poniendo el valor 50 en la columna SALES de la fila correspondiente a Espresso. La actualizaci�n afecta s�lo a una l�nea de la tabla, por eso n es igual a 1.

Cuando el m�todo executeUpdate es utilizado para ejecutar una sentecia DDL, como la creaci�n de una tabla, devuelve el int: 0. Consecuentemente, en el siguiente fragmento de c�digo, que ejecuta la sentencia DDL utilizada pra crear la tabla COFFEES, n tendr� el valor 0.

int n = executeUpdate(createTableCoffees); // n = 0

Observa que cuando el valor devuelto por executeUpdate sea 0, puede significar dos cosas: (1) la sentencia ejecutada no ha actualizado ninguna fila, o (2) la sentencia ejecutada fue una sentencia DDL.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR