El uso de JDBC Prepared Statement es hoy en día prácticamente obligatorio. Aún así hay muchas veces que nos olvidamos de de como usarlos ya que son los frameworks de persistencia los que los utilizan de forma transparente por nosotros. Aún así hay situaciones en las cuales nos podemos encontrar con la necesidad de hacer uso de ellos de forma directa. ¿Cómo funcionan exactamente los JDBC Prepared Statement ?
Utilizando JDBC Prepared Statement
Lo primero que tenemos que entender es cual es la diferencia entre un Statement de JDBC y un Prepared Statement. Cuando nosotros construimos una consulta normal de JDBC utilizamos un Statement, este Statement o sentencia lo que se encarga es de definir una consulta SQL a ejecutar contra el motor de la base de datos.
Connection conexion = DriverManager.getConnection("jdbc:mysql://localhost/prueba", "root","root"); Statement sentencia = conexion.createStatement(); String nombre="pepe"; String consulta = "select * from Persona where nombre='"+nombre+"'"; ResultSet rs=sentencia.executeQuery(consulta);
En este caso estamos construyendo una sentencia y aportando un parámetro a la consulta de forma dinámica. Esto básicamente se convierte en una consulta SQL que nosotros ejecutamos vía el driver JDBC contra la base de datos.
Muchas veces se nos olvida que para cada consulta SQL que construimos contra la base de datos se construye un plan de ejecución en el que la base de datos decide como esa consulta se ejecuta.
A dos consultas diferentes se crean dos planes de ejecución diferentes aunque ambas consultas sean realmente muy similares y únicamente entre en juego el valor del parámetro que las pasamos . Para solventar este problema existen los JDBC Prepared statement . Estas estructuras permiten mantener las consultas neutras sin tener en cuenta los parámetros que se las pasa ya que realiza un binding de ellos
De esta forma cuando la base de datos genera un hash para el plan de ejecución ambas consultas , la que consulta por pepe y la que consulta por ana devuelven el mismo hash y comparten el plan de ejecución. Vamos a ver esto en código:
String consulta = "select * from Persona where nombre = ? "; Connection conexion= DriverManager.getConnection("jdbc:mysql://localhost/prueba", "root", "root"); PreparedStatement sentencia= conexion.prepareStatement(consulta); sentencia.setString(1, "pepe"); ResultSet rs = sentencia.executeQuery();
No solo nos estaremos ahorrando la construcción de planes de ejecución sino que también de la misma manera estamos evitando que nos inyecten SQL ya que al parametrizar la consulta el API de JDBC nos protege contra las este tipo de ataques.Normalmente el uso de consultas parametrizadas mejora el rendimiento entre un 20 y un 30 % a nivel de base de datos.
JDBC Prepared Statement y Logs
Hay situaciones en las que necesitamos realizar un log de la consulta SQL , al tratarse de una sentencia preparada solemos hacer un log del String algo como por ejemplo.
String consulta = "select * from Persona where nombre = ? "; log(consulta);
Esto a veces puede ser un problema ya que perdemos los parámetros que se pasan . Sin embargo muchos drivers soportan el log de la propia consulta SQL con los parámetros ya aplicados realizando un log de la propia sentencia
String consulta = "select * from Persona where nombre = ? "; PreparedStatement ps = con.prepareStatement(consulta); ps.setString(1, nombre); log(ps);
Tengámoslo en cuenta , en este caso podremos ver salir por la consola algo del siguiente estilo:
com.mysql.jdbc.JDBC42PreparedStatement@67424e82: select * from Persona where nombre='juan'
El parámetro aparece.
Otros artículos relacionados
Muy buen tutorial, siempre se me olvida la síntaxis de los prepared statement; no sabía que las consultas eran más eficientes con p.s. a nivel de base de datos, fascinante, muchas gracias y Bendiciones!.
de nada 🙂
Hola , como estas
Que puede ser que quiero usar setString() y me dice que el metodo es inexitente.
Uso Netbeans
muchas gracias
revisa si has usado preparedstatement
Buenos dias es posible parametrizar el esquema en una consulta por ejemplo “SELECT * FROM ?.TABLA” ???
Gracias
Si sin problema otra cosa es que hacer con la estructura que se devuelve.
Hola,
Cual de las dos opciones:
Statement sentencia = conexion.createStatement();
o
PreparedStatement sentencia= conexion.prepareStatement(consulta);
puede crear un bloqueo de tablas?
Ninguna de ellas , Puedes tener un problema de cierre de conexiones
¿El precio de los cursos es en dólares americanos?
Si , pero recuerda que en estos momentos esta activo un descuento del 70% aprovechalo 🙂
Buenos dias.
Puedo visualizar que tiene un curso de SPRING en pago, quisiera saber cuanto es el tiempo de duracion del curso, si esta actualizado a su ultima version y si se realiza algun proyecto que se aplique a la realidad con todo lo aprendido, gracias por la respuesta.
El curso son unas 7 horas de videos .Una vez comprado te le quedas para siempre . Aborda el desarrollo completo de una aplicación con Spring y Buenas prácticas. El curso al que hago referencia es Arquitectura Java Solida con Spring
Gracias viejo, pase como 4 horas dando me en la torre, porque en Phpmyadmin corre sin las benditas ” es decir
“Where Carrera = ” + carrera + ” “; Jajajaja
Desde Java es de poner ”
“Where Carrera= ‘ ” + carrera + ” ‘ “;
Y estaba abatido, desesperado XD
me alegro que te fuera util 🙂
Cecilio: Buenas tardes, queria preguntarte porque generalmente se define la conexion y el PreparedStatement fuera del try. Te planteo un ejemplo: import com.educacionit.jse.integrador.excepciones.NegocioException; public class ProductoDAO { public static void inserta(Producto p) throws NegocioException, CafeStoreException { Connection con = null; PreparedStatement st = null; try { con = AdministradorDeConexiones.obtenerConexion(); if (existe(p.getDescripcion())) { throw new NegocioException(“El producto ya existe”); } String sql = “insert into Producto (precio, descripcion) values (?,?)”; st = con.prepareStatement(sql); st.setDouble(1, p.getPrecio()); st.setString(2, p.getDescripcion()); st.execute(); } catch (Exception e) { throw new CafeStoreException(); } finally { try { st.close(); con.close(); } catch (SQLException e) { e.printStackTrace(); throw new… Read more »
Lo que han declarado es la definición de la variable , pero la han instanciado dentro del try. Siempre las cosas se pueden afinar un poco , pero vamos puede ser hasta código legado que le hayan añadido cosas. En cuanto a interfaces y clases .Oracle define los interfaces y cada driver los implementa como clases. echa un vistazo al artículo:
JDBC Driver, un concepto clave
Hola Cecilio!
Sabes si es necesario usar el patrón Singleton (y cual sería la mejor forma de usarlo) para el manejo de los objetos Connection, Statement o PreparedStatement.
Saludos!
Ninguna debe ser singleton , a ver si explico un poco esto mas a detalle
Hola Cecilio,
Disculpa tu por casualidad sabes como puedo pasar parametros desde Java a un JSP, ya valido en Java si el usuario tiene una session iniciada pero necesito mostrarle un mensaje en pantalla que ya posee una session en el navegador XXXX, pero esto seria usando swal de java. si me puedes guiar te lo agradecere.
Saludos
almacenaria un hashmap en el servlet context con los usuasrios que tienen inicializada sessión si ese usuario se logea y ya esta en la lista , pues es que estaba repetido y no le valido o le aviso que pierde la otra