Ejemplo con preparedStatement

Viene de createStatement()

Qué es una prepared statement

Una Prepared Statement es una sentencia SQL de base de datos precompilada. Al estar precompilada, su ejecución será más rápida que una SQL normal, por lo que es adecuada cuando vamos a ejecutar la misma sentencia SQL (con distintos valores) muchas veces. Por ejemplo, estas dos inserciones MySQL normales

mysql> INSERT INTO person VALUES (null, 23, 'Pedro', 'Perez'); 
mysql> INSERT INTO person VALUES (null, 33, 'Rodrigo', 'Rodriquez');

podrían hacerse por medio de una Prepared Statement de esta forma

mysql> PREPARE insertar FROM "INSERT INTO person VALUES (null, ?, ?, ?)";

mysql> SET @edad=23;
mysql> SET @nombre='Pedro'; 
mysql> SET @apellido='Perez';
mysql> EXECUTE insertar USING @edad,@nombre,@apellido

mysql> SET @edad=33;
mysql> SET @nombre='Rodrigo'; 
mysql> SET @apellido='Rodriguez';
mysql> EXECUTE insertar USING @edad,@nombre,@apellido;

mysql> DEALLOCATE PREPARE insertar;

Uso desde java

Para poder usar una Prepared Statement real desde java, es necesario que tanto la base de datos como el driver java que usemos soporten las Prepared Statement. Independientemente de que lo soporten o no, nosotros podremos hacer el código java usando Prepared Statement, aunque si la base de datos o el driver no lo soportan, no obtendríamos la ventaja de la eficiencia.

Por ejemplo, MySQL sí soporta los Prepared Statement y los driver modernos de MySQL para java también lo soportan. Sin embargo, debemos habilitarlos en el momento de establecer la conexión

Connection conexion = DriverManager.getConnection(
      "jdbc:mysql://servidor/basedatos?useServerPrepStmts=true",
      "usuario", "password");

Fíjate en que en la URL de conexión hemos añadido un parámetro ?useServerPrepStmts=true. Para otras bases de datos deberás ver cómo es la cadena de conexión que habilite el uso de Prepared Statement si no lo están por defecto.

Un poco de código java

Para usar una Prepared Statement desde java, el código puede ser como este

PreparedStatement psInsertar = conexion.prepareStatement(
            "insert into person values (null,?,?,?)");

psInsertar.setInt(1, 23); // La edad, el primer interrogante, es un entero. 
psInsertar.setString(2, "Pedro"); // El String nombre es el segundo interrogante
psInsertar.setString(3, "Perez"); // Y el tercer interrogante, un String apellido.
psInsertar.exequteUpdate(); // Se ejecuta la inserción.
...
psInsertar.setInt(1, 12); // La edad, el primer interrogante, es un entero. 
psInsertar.setString(2, "Juan"); // El String nombre es el segundo interrogante
psInsertar.setString(3, "Lopez"); // Y el tercer interrogante, un String apellido.
psInsertar.exequteUpdate(); // Se ejecuta la inserción.

Símplemente ponemos interrogantes donde irán los valores concretos que vayamos a insertar. Cada interrogante se identifica luego con un número, de forma que el primer interrogante que aparece es el 1, el segundo el 2, etc. Luego, con los métodos set() correspondientes rellenamos esos valores. El primer parámetro es el número del interrogante y el segundo el valor que queremos insertar. Finalmente llamamos a executeUpdate(). Luego, con la misma PreparedStatement, ponemos otros valores volviendo a llamar a los métodos set() y volvemos a llamar a executeUpdate()

Fíjate que a la hora de poner los interrogantes, no nos hemos preocupado de poner comillas en los valores de texto ni conversiones de ningún tipo. Las llamadas a setInt(), setString(), ya hacen todas las conversiones adecuadas para nosotros.

No es necesario verificar las cadenas

Y el que esta conversión sea automática es una ventaja adicional si los datos los ha introducido el usuario. Como comentamos en transacciones con base de datos, si usamos una Statement normal, nosotros tenemos que componer la cadena con la SQL con algo como esto

String sql = "insert into person values (null, " +
   edad + ",'" + nombre + "','" + apellido + "')";

y si algún desalmado mete en su nombre una comilla simple, como O'Donnell, entonces la cadena SQL quedaría

insert into person values (null, 23, 'O'Donnell', 'Perez')

que está mal construida por parecer que el nombre el 'O' y lo de Donnell que hay detrás no está bien construido en SQL. La ejecución daría un error.

Por ello, si los datos los va a introducir un usuario, es buena idea usar PreparedStatement, aunque no vayamos a usar la eficiencia real de las PreparedStatement. La otra opción es que nosotros con código verifiquemos la validez de esos datos.

Sigue en callableStatement()