¿Cuándo debemos usar un PreparedStatement en lugar de un Statement?

Conozco las ventajas de usar PreparedStatement , que son

  • la consulta es reescrita y comstackda por el servidor de la base de datos
  • protección contra inyección de SQL

Pero, ¿quiero saber cuándo lo usamos en lugar de Statement ?

  1. Query es reescrito y comstackdo por el servidor de la base de datos

    Si no usa una statement preparada, el servidor de la base de datos tendrá que analizar y calcular un plan de ejecución para la statement cada vez que la ejecute. Si encuentra que ejecutará la misma statement varias veces (con diferentes parámetros), entonces vale la pena preparar la statement una vez y reutilizar esa statement preparada. Si está consultando la base de datos adhoc, probablemente haya poco beneficio.

  2. Protegido contra inyección SQL

    Esta es una ventaja que casi siempre desea, por lo tanto, es una buena razón para usar un Estado PreparedStatement cada vez. Es una consecuencia de tener que parametrizar la consulta, pero hace que correrla sea mucho más seguro. La única vez que puedo pensar que esto no sería útil es si permitía consultas de bases de datos adhoc; Puede usar simplemente el objeto Statement si estuvo creando un prototipo de la aplicación y es más rápido para usted, o si la consulta no contiene parámetros.

Pregúntale a Tom:

El uso de un Statement en JDBC debe estar 100% localizado para ser usado para DDL (ALTER, CREATE, GRANT, etc.) ya que estos son los únicos tipos de statement que no pueden aceptar BIND VARIABLES.

PreparedStatements o CallableStatements se deben usar para CADA OTRO tipo de instrucción (DML, Consultas). Como estos son los tipos de statement que aceptan variables de vinculación.

Esto es un hecho, una regla, una ley: use declaraciones preparadas POR TODAS PARTES. Use DECLARACIONES casi en ninguna parte.

Está hablando específicamente de Oracle, pero el mismo principio se aplica a cualquier base de datos que almacena en caché los planes de ejecución.

¿Aplicaciones de base de datos que escalan y previenen ataques de inyección SQL al mismo tiempo? ¿Cuál es el inconveniente?

Daría la vuelta a esto: en una aplicación distribuida públicamente, generalmente siempre debes usar declaraciones preparadas a menos que tengas una razón realmente convincente para no hacerlo , y siempre debes proporcionar los parámetros “correctamente” a la statement preparada, y no empalmándolos en el cadena de consulta.

¿Por qué? Bueno, básicamente por las razones que diste (o al menos, la segunda) …

Los estados preparados deben usarse con mucho cuidado en las cláusulas WHERE.

Supongamos que una tabla se define como:

 create table t (int o, k varchar(100), v varchar(100)) 

(por ejemplo, “o: object-ID (clave externa), k: attribute-key, v: attribute-value”).

Además hay un índice (no único) en v.

 create index ixt on t ( v ) 

Supongamos que esta tabla contiene 200 millones de filas insertadas como:

 for (i = 0; i < 100*1000*1000; i++) { insert into t (o,k,v) values (i,'k1','v1'); insert into t (o,k,v) values (i,'k2', Convert(i, varchar)); } 

("Por lo tanto, cada objeto o tiene atributos k1 = v1 y k2 = o")

Entonces no deberías construir consultas como:

 select o,p,v from t as tx, t as ty where tx.o=ty.o and tx.k=? and tx.v=? and ty.k=? and ty.v=? 

("encuentra objetos que tienen dos atributos dados")

Mi experiencia con ORACLE y MSSQL es que esas consultas pueden tardar muchos minutos en regresar. Esto es cierto incluso si ninguna fila coincide con la cláusula where. Depende de si el servidor SQL decide buscar primero tx.v o ty.v.

Una vez, coloque los valores de las columnas k y v en la instrucción. Creo que esto se debe a que los Servidores SQL toman en cuenta los valores al calcular el plan de ejecución.

Una consulta similar a esto vuelve siempre después de milisegundos:

 select o,p,v from t as tx, t as ty where tx.o=ty.o and tx.k='k1' and tx.v='v1' and ty.k='k2' and ty.v='1234' 

("SQL-Server siempre buscará primero v = '1234' y luego para v = 'v1'")

Saludos
Wolfgang

Prefiero usar PreparedStatement si quiero ejecutar una consulta. (Insertar, Seleccionar, … etc.). El mismo rasoson que otros escritos arriba.

Pero si necesito usar parámetros dynamics , uso simplemente Statement porque puedo construir fácilmente mi cadena SQL que simplemente ejecutar. (inmyopinion) Si quieres construir una consulta dinámica con preparedStatment tendrás un gran código de spaghetti que nadie entiende.

Además de evitar la inyección de SQL, la portabilidad del formato (que no se puede obtener de Statement ), el rendimiento es la razón obvia. Sin embargo, PreparedStatement no viene sin ninguna penalización. Por ejemplo, generalmente es más lento que Statement si se ejecuta solo una vez, ya que hay una sobrecarga. Por lo tanto, la idea general es PreparedStatement debe usar cuando se realiza la misma consulta muchas veces. Sin embargo, la cantidad de sobrecarga es muy específica para la implementación del servidor de base de datos, por lo que exactamente cuándo elegir PreparedStatement sobre Statement , desde la consideración del rendimiento, realmente debería basarse en su experiencia real / experimentos de un servidor de base de datos específico.

Declaración : cada vez que se ejecuta la consulta sql, esta instrucción sql se envía al DBMS donde se comstack. Por lo tanto, aumenta las cargas del servidor y disminuye el rendimiento.

 connection con=null; String sql="select * from employee where id=5"; Statement st=conn.createStatement(); 

PreparedStatement : A diferencia de Statement, PreparedStatement recibe una consulta sql como parámetro cuando se crea.

 connection con=null; String sql="select * from employee where id=?"; PreparedStatement ps=conn.prepareStatement(sql); 

Esta instrucción SQL se envía a la Base de datos donde se comstack. Entonces, en preparedStatement compiled ocurre una sola vez pero en el enunciado comstackdo ocurre cada vez que se invoca a Statement.