La déclaration préparée est une version légèrement plus puissante d'une déclaration et doit toujours être au moins aussi rapide et facile à gérer qu'une déclaration.
La déclaration préparée peut être paramétrée
La plupart des bases de données relationnelles gèrent une requête JDBC / SQL en quatre étapes:
- Analyser la requête SQL entrante
- Compiler la requête SQL
- Planifier / optimiser le chemin d'acquisition des données
- Exécuter la requête optimisée / acquérir et renvoyer des données
Une instruction effectuera toujours les quatre étapes ci-dessus pour chaque requête SQL envoyée à la base de données. Une instruction préparée pré-exécute les étapes (1) - (3) du processus d'exécution ci-dessus. Ainsi, lors de la création d'une instruction préparée, une pré-optimisation est effectuée immédiatement. L'effet est de réduire la charge sur le moteur de base de données au moment de l'exécution.
Maintenant, ma question est la suivante: "Y a-t-il un autre avantage à utiliser la déclaration préparée?"
Réponses:
Avantages d'un
PreparedStatement
:La précompilation et la mise en cache côté DB de l'instruction SQL permettent une exécution globale plus rapide et la possibilité de réutiliser la même instruction SQL par lots .
Prévention automatique des attaques par injection SQL par échappement intégré des guillemets et autres caractères spéciaux. Notez que cela nécessite que vous utilisiez l'une des méthodes pour définir les valeurs
PreparedStatement
setXxx()
et donc ne pas aligner les valeurs dans la chaîne SQL par concaténation de chaîne.
Soulage réglage d'objets non standard Java dans une chaîne SQL, par exemple
Date
,Time
,Timestamp
,BigDecimal
,InputStream
(Blob
) etReader
(Clob
). Sur la plupart de ces types, vous ne pouvez pas "simplement" fairetoString()
comme vous le feriez dans un simpleStatement
. Vous pouvez même refactoriser le tout pour l'utiliserPreparedStatement#setObject()
dans une boucle, comme illustré dans la méthode utilitaire ci-dessous:Qui peut être utilisé comme ci-dessous:
la source
Statement
, mais cela peut valoir la peine d'être testé.Ils sont précompilés (une fois), donc plus rapidement pour l'exécution répétée de SQL dynamique (lorsque les paramètres changent)
La mise en cache des instructions de base de données améliore les performances d'exécution de la base de données
Les bases de données stockent des caches de plans d'exécution pour les instructions précédemment exécutées. Cela permet au moteur de base de données de réutiliser les plans des instructions qui ont été exécutées précédemment. Étant donné que PreparedStatement utilise des paramètres, chaque fois qu'il est exécuté, il apparaît comme le même SQL, la base de données peut réutiliser le plan d'accès précédent, ce qui réduit le traitement. Les instructions "insèrent" les paramètres dans la chaîne SQL et n'apparaissent donc pas comme le même SQL dans la base de données, ce qui empêche l'utilisation du cache.
Le protocole de communication binaire signifie moins de bande passante et des appels de communication plus rapides vers le serveur DB
Les instructions préparées sont normalement exécutées via un protocole binaire non SQL. Cela signifie qu'il y a moins de données dans les paquets, donc les communications avec le serveur sont plus rapides. En règle générale, les opérations réseau sont un ordre de grandeur plus lent que les opérations sur disque qui sont un ordre de grandeur plus lent que les opérations CPU en mémoire. Par conséquent, toute réduction de la quantité de données envoyées sur le réseau aura un bon effet sur les performances globales.
Ils protègent contre l'injection SQL, en échappant du texte pour toutes les valeurs de paramètre fournies.
Ils offrent une séparation plus forte entre le code de la requête et les valeurs des paramètres (par rapport aux chaînes SQL concaténées), améliorant la lisibilité et aidant les responsables du code à comprendre rapidement les entrées et les sorties de la requête.
En java, peut appeler getMetadata () et getParameterMetadata () pour réfléchir respectivement sur les champs du jeu de résultats et les champs des paramètres
En java, accepte intelligemment les objets java en tant que types de paramètres via setObject, setBoolean, setByte, setDate, setDouble, setDouble, setFloat, setInt, setLong, setShort, setTime, setTimestamp - il se convertit au format de type JDBC qui est compréhensible pour la base de données (pas seulement pour Strings) () format).
En java, accepte les tableaux SQL, comme type de paramètre via la méthode setArray
En java, accepte les CLOBs, BLOBs, OutputStreams et Readers comme "flux" de paramètres via les méthodes setClob / setNClob, setBlob, setBinaryStream, setCharacterStream / setAsciiStream / setNCharacterStream, respectivement
En java, permet de définir des valeurs spécifiques à la base de données pour SQL DATALINK, SQL ROWID, SQL XML et NULL via les méthodes setURL, setRowId, setSQLXML et setNull
En java, hérite de toutes les méthodes de Statement. Il hérite de la méthode addBatch et permet en outre d'ajouter un ensemble de valeurs de paramètres pour correspondre à l'ensemble de commandes SQL par lots via la méthode addBatch.
En java, un type spécial de PreparedStatement (la sous-classe CallableStatement) permet d'exécuter des procédures stockées - prenant en charge les hautes performances, l'encapsulation, la programmation procédurale et SQL, l'administration / la maintenance / le peaufinage de la logique de la base de données et l'utilisation de la logique et des fonctionnalités de la propriété intellectuelle de la base de données
la source
Connection.createStatement
etConnection.prepareStatement
. Cette conception vous oblige à travailler contre des interfaces, vous n'avez donc pas besoin de connaître les classes d'implémentation spécifiques et d'éviter un couplage étroit inutile avec de telles classes d'implémentation. Le tout expliqué avec des exemples dans les documents Java jdbc et Java docs. :)PreparedStatement
est une très bonne défense (mais pas infaillible) pour empêcher les attaques par injection SQL . La liaison des valeurs des paramètres est un bon moyen de se prémunir contre les "petites tables Bobby" qui font une visite indésirable.la source
ORDER BY
) et / ou des constantes numériques dans certains endroits (penserLIMIT
,OFFSET
et d' autres solutions de pagination), alors ceux - ci peuvent être attaqués par injection SQL, même lorsque les commandes préparées et le paramétrage est utilisé chaque fois que possible.Certains des avantages de PreparedStatement sur Statement sont les suivants:
En savoir plus sur le problème d'injection SQL sur http://www.journaldev.com/2489/jdbc-statement-vs-preparedstatement-sql-injection-example
la source
rien à ajouter,
1 - si vous souhaitez exécuter une requête en boucle (plus d'une fois), l'instruction préparée peut être plus rapide, en raison de l'optimisation que vous avez mentionnée.
2 - la requête paramétrée est un bon moyen d'éviter l'injection SQL. Les requêtes paramétrées ne sont disponibles que dans PreparedStatement.
la source
La déclaration est statique et la déclaration préparée est dynamique.
La déclaration convient au DDL et le relevé préparé au DML.
L'instruction est plus lente tandis que l'instruction préparée est plus rapide.
plus de différences (archivé)
la source
Impossible de faire des CLOB dans une déclaration.
Et: (OraclePreparedStatement) ps
la source
Comme cité par mattjames
la source
l'injection SQL est ignorée par l'instruction préparée, la sécurité est donc augmentée dans l'instruction préparée
la source
la source
L'instruction sera utilisée pour exécuter des instructions SQL statiques et elle ne peut pas accepter les paramètres d'entrée.
PreparedStatement sera utilisé pour exécuter des instructions SQL plusieurs fois de manière dynamique. Il acceptera les paramètres d'entrée.
la source
Autre caractéristique de la requête préparée ou paramétrée: référence tirée de cet article.
Cette instruction est l'une des fonctionnalités du système de base de données dans laquelle la même instruction SQL s'exécute de manière répétée avec une grande efficacité. Les instructions préparées sont un type de modèle et sont utilisées par l'application avec différents paramètres.
Le modèle d'instruction est préparé et envoyé au système de base de données et le système de base de données effectue l'analyse, la compilation et l'optimisation sur ce modèle et le stocke sans l'exécuter.
Certains paramètres tels que, où la clause n'est pas transmise lors de la création ultérieure du modèle d'application, envoient ces paramètres au système de base de données et au système de base de données utilisent le modèle de l'instruction SQL et s'exécute selon la demande.
Les instructions préparées sont très utiles contre SQL Injection car l'application peut préparer des paramètres à l'aide de différentes techniques et protocoles.
Lorsque le nombre de données augmente et que les index changent fréquemment à ce moment, les instructions préparées peuvent échouer car dans cette situation, un nouveau plan de requête est nécessaire.
la source
Statement
l'interface exécute des instructions SQL statiques sans paramètresPreparedStatement
L'interface (instruction d'extension) exécute une instruction SQL précompilée avec / sans paramètresEfficace pour les exécutions répétées
Il est précompilé donc c'est plus rapide
la source
Ne vous trompez pas: souvenez-vous simplement
la source
J'ai suivi toutes les réponses à cette question pour changer un code hérité fonctionnant en utilisant -
Statement
(mais ayant des injections SQL) en une solution utilisantPreparedStatement
avec un code beaucoup plus lent en raison d'une mauvaise compréhension de la sémantique autour deStatement.addBatch(String sql)
&PreparedStatement.addBatch()
.Je liste donc mon scénario ici pour que les autres ne commettent pas la même erreur.
Mon scénario était
Donc, dans le code ci-dessus, j'avais des milliers de requêtes différentes, toutes ajoutées à la même instruction et ce code fonctionnait plus rapidement car les instructions non mises en cache étaient bonnes et ce code était rarement exécuté dans l'application.
Maintenant, pour corriger les injections SQL, j'ai changé ce code en,
Donc, vous voyez, j'ai commencé à créer des milliers d'
PreparedStatement
objets et je n'ai finalement pas pu utiliser le traitement par lots parce que mon scénario exigeait cela - il y a des milliers de requêtes UPDATE ou INSERT et toutes ces requêtes se trouvent être différentes.La fixation de l'injection SQL était obligatoire sans aucun coût de dégradation des performances et je ne pense pas que ce soit possible
PreparedStatement
dans ce scénario.De plus, lorsque vous utilisez la fonction de traitement par lots intégrée, vous devez vous soucier de ne fermer qu'une seule instruction, mais avec cette approche de liste, vous devez fermer l'instruction avant de la réutiliser, Réutiliser une instruction préparée
la source