java utilisation Quand devrions-nous utiliser un PreparedStatement au lieu d'un Statement?




utilisation preparedstatement (7)

Je connais les avantages d’utiliser PreparedStatement , qui sont

  • la requête est réécrite et compilée par le serveur de base de données
  • protection contre l'injection SQL

Mais je veux savoir quand nous l'utilisons au lieu de Statement ?


PreparedStatements devrait être utilisé très soigneusement dans les clauses WHERE.

Supposons qu'une table soit définie comme:

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

(par exemple "o: ID-objet (clé étrangère), k: clé-attribut, v: valeur-attribut").

En outre, il existe un index (non unique) sur v.

create index ixt on t ( v )

Supposons que cette table contienne 200 millions de lignes insérées comme:

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));
}

("Ainsi, chaque objet o a des attributs k1 = v1 et k2 = o")

Ensuite, vous ne devez pas créer de requêtes comme:

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=?

("trouver des objets qui ont deux attributs donnés")

Mon expérience avec ORACLE et MSSQL est que ces requêtes peuvent nécessiter plusieurs minutes pour revenir. Cela est vrai même si aucune ligne ne correspond à la clause where. Cela dépend si le serveur SQL décide de rechercher tx.v ou ty.v en premier.

On devrait mettre les valeurs pour les colonnes k et v directement dans l'énoncé. Je pense que c'est parce que les serveurs SQL prennent en compte les valeurs lors du calcul du plan d'exécution.

Une requête ressemble à ceci renvoie toujours après des millisecondes:

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'

("Le serveur SQL recherchera toujours d'abord v = '1234' et ensuite pour v = 'v1'")

Cordialement
Wolfgang


Vous pouvez toujours utiliser PreparedStatement au lieu de Statment (sélectionner, insérer, mettre à jour, supprimer). De meilleures performances et protégées contre les injections SQL.

Mais, ne l'utilisez pas avec une requête dynamique comme une requête avec la WHERE variable IN [ hundreds possibilities ] :

  1. C'est contre-productif, vous avez perdu de la performance et de la mémoire car vous mettez en cache chaque fois une nouvelle demande, et PreparedStatement ne se limite pas à l'injection SQL, il s'agit de performances. Dans ce cas, Statement ne sera pas plus lent.

  2. Votre pool a une limite de PreparedStatment (-1 par défaut mais vous devez le limiter), et vous atteindrez cette limite! et si vous n'avez aucune limite ou très grande limite, vous avez un risque de fuite de mémoire et, dans les cas extrêmes, des erreurs OutofMemory. Donc, si c'est pour votre petit projet personnel utilisé par 3 utilisateurs, ce n'est pas dramatique, mais vous ne le voulez pas si vous êtes dans une grande entreprise et que votre application est utilisée par des milliers de personnes et des millions de demandes.

Quelques lectures IBM: considérations relatives à l'utilisation de la mémoire lors de l'utilisation de la mise en cache d'instructions préparées


Je préfère utiliser PreparedStatement si je veux exécuter une requête. (Insert, Select, ... etc). Le même rasoson que d'autres écrit ci-dessus.

Mais si j'ai besoin d'utiliser des paramètres dynamiques, j'utilise simplement Statement parce que je peux facilement construire ma chaîne SQL simplement exécutée. (InMyopinion) Si vous voulez construire une requête dynamique avec prepareStatment, vous aurez un énorme code spaghetti que personne ne comprend.


Outre la prévention de l'injection SQL, la portabilité du formatage (que vous ne pouvez pas obtenir à partir de Statement ), la performance est la raison évidente. Cependant, PreparedStatement ne vient pas sans pénalité. Par exemple, il est généralement plus lent que Statement s'il n'est exécuté qu'une seule fois, car il y a des frais généraux. L'idée générale est que PreparedStatement doit être utilisé lorsque vous effectuez plusieurs fois la même requête. Cependant, le temps nécessaire à la mise en œuvre de PreparedStatement sur Statement , à partir des performances, dépend de votre expérience / expérience réelle d'un serveur de base de données spécifique.


  1. La requête est réécrite et compilée par le serveur de base de données

    Si vous n'utilisez pas d'instruction préparée, le serveur de base de données doit analyser et calculer un plan d'exécution pour l'instruction chaque fois que vous l'exécutez. Si vous trouvez que vous exécuterez la même instruction plusieurs fois (avec des paramètres différents), il vaut mieux préparer une fois l'instruction et réutiliser cette instruction préparée. Si vous interrogez la base de données adhoc, cela ne présente probablement aucun avantage.

  2. Protégé contre l'injection SQL

    Ceci est un avantage que vous voulez presque toujours par conséquent une bonne raison d'utiliser un PreparedStatement chaque fois. C'est une conséquence de devoir paramétrer la requête, mais cela rend le fonctionnement beaucoup plus sûr. La seule fois où je peux penser que cela ne serait pas utile, c'est si vous autorisiez des requêtes de base de données ad hoc; Vous pouvez simplement utiliser l'objet Statement si vous faites un prototypage de l'application et que c'est plus rapide pour vous, ou si la requête ne contient aucun paramètre.


Je voudrais tourner ce tour: dans une application distribuée publiquement, vous devez généralement toujours utiliser des instructions préparées à moins que vous ayez une raison convaincante de ne pas le faire , et vous devez toujours fournir les paramètres "correctement" à l'instruction préparée. chaîne de requête.

Pourquoi? Eh bien, essentiellement à cause des raisons que vous avez données (ou du moins, la deuxième) ...


Demandez l' opinion de Tom:

L'utilisation d'une instruction dans JDBC doit être localisée à 100% sur DDL (ALTER, CREATE, GRANT, etc.), car ce sont les seuls types d'instructions qui ne peuvent pas accepter les variables BIND.

PreparedStatements ou CallableStatements doivent être utilisés pour TOUS les autres types d'instructions (DML, Queries). Comme ce sont les types d'instruction qui acceptent les variables de liaison.

C'est un fait, une règle, une loi - utilisez des déclarations préparées PARTOUT. Utilisez les déclarations presque pas où.

Il parle spécifiquement d'Oracle mais le même principe s'applique à toute base de données qui met en cache les plans d'exécution.

Des applications de base de données qui adaptent et empêchent les attaques par injection SQL en même temps? Quel est l'inconvénient?





prepared-statement