Question

Une chose qui a toujours été pénible est de consigner les erreurs SQL (JDBC) lorsque vous avez un PreparedStatement au lieu de la requête elle-même.

Vous vous retrouvez toujours avec des messages tels que:

2008-10-20 09:19:48,114 ERROR LoggingQueueConsumer-52 [Logger.error:168] Error 
executing SQL: [INSERT INTO private_rooms_bans (room_id, name, user_id, msisdn, 
nickname) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE room_id = ?, name = ?, 
user_id = ?, msisdn = ?, nickname = ?]

Bien sûr, je pourrais écrire une méthode d'assistance pour récupérer les valeurs et analyser / substituer les points d'interrogation par des valeurs réelles (et suivrai probablement cette voie si je n'obtiens pas le résultat de cette question), mais je voulais juste savoir si ce problème a déjà été résolu par quelqu'un d'autre et / ou s'il existe un assistant de journalisation générique qui le ferait automatiquement pour moi.

Modifié après quelques réponses:

Les bibliothèques fournies jusqu’à présent semblent convenir à la consignation des instructions à des fins de débogage, ce qui est sans aucun doute utile. Cependant, je cherche un moyen de prendre un PreparedStatement lui-même (pas une sous-classe) et de consigner son instruction SQL chaque fois qu'une erreur se produit. Je ne voudrais pas déployer une application de production avec une implémentation alternative de PreparedStatement.

Je suppose que je recherche une classe utilitaire et non une spécialisation PreparedStatement.

Merci!

Était-ce utile?

La solution

J'ai essayé log4jdbc et le travail a été fait pour moi.

NOTE DE SÉCURITÉ: À compter d'août 2011, les résultats consignés d'une instruction préparée par log4jdbc ne sont pas sûrs d'exécuter. Ils peuvent être utilisés pour l'analyse, mais ne doivent JAMAIS être réintroduits dans un SGBD.

Exemple de journal généré par logjdbc:

  

2010/08/12 16:30:56 jdbc.sqlonly   org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate (DelegatingPreparedStatement.java:105)   8. INSERT INTO A_TABLE   (ID_FILE, CODE1, ID_G, ID_SEQUENCE, REF, NOM, BARRE, IDENTIFIANT, AMOUNT, DESCRIPTION, ÉTAT, CODE2, REJECT_DESCR, ID_CUST_REJ)   VALEURS   (2, '123', 1, '2', 'aa', 'awe', null, '0123', 4317.95, 'Rccc', '0', null, null, null)

La bibliothèque est très facile à configurer:

Ma configuration avec HSQLDB :

jdbc.url=jdbc:log4jdbc:hsqldb:mem:sample

Avec Oracle :

jdbc.url=jdbc:log4jdbc:oracle:thin:@mybdd:1521:smt
jdbc.driverClass=net.sf.log4jdbc.DriverSpy

logback.xml:

<logger name="jdbc.sqlonly" level="DEBUG"/>

Dommage que ce ne soit pas sur un référentiel Maven, mais toujours utile.
De ce que j'ai essayé, si vous définissez

Vous n'obtiendrez que les déclarations erronées. Cependant, je ne sais pas si cette bibliothèque a un impact sur les performances.

Autres conseils

Cela dépend beaucoup de la base de données. Par exemple, je comprends que certains pilotes JDBC (par exemple, sybase, peut-être ms-sql) gèrent les instructions préparées en créant une procédure stockée temporaire sur le serveur, puis en appelant cette procédure avec les arguments fournis. Ainsi, le code SQL complet n'est jamais réellement transmis par le client.

En conséquence, l'API JDBC n'expose pas les informations que vous recherchez. Vous pourrez peut-être transtyper vos objets d'instructions avec l'implémentation du pilote interne, mais probablement pas. Votre serveur d'applications pourrait bien envelopper les instructions dans sa propre implémentation.

Je pense que vous devrez peut-être mordre la balle et écrire votre propre classe qui interpole les arguments dans le code de substitution SQL. Ce sera gênant, car vous ne pouvez pas demander à PreparedStatement les paramètres qui ont été définis. Vous devrez donc les mémoriser dans un objet d'assistance avant de les transmettre à l'instruction.

Il me semble que l’une des bibliothèques d’utilitaires qui encapsule les objets d’implémentation de votre pilote est la manière la plus pratique de réaliser ce que vous essayez d’atteindre, mais cela va être désagréable dans les deux cas.

Utilisez P6Spy : son Oracle, Mysql, JNDI, JMX, Printemps et Maven amis. Hautement configurable. Intégration simple et bas niveau Peut imprimer le chemin de pile . Ne peut imprimer que les appels lourds - en fonction de la durée.

  1. Si vous utilisez MySQL, le fichier PreparedStatement.toString () de MySQL Connector inclure les paramètres liés . Bien que les pools de connexions tierces puissent rompre cela.

  2. Sous-classe PreparedStatement pour construire la chaîne de requête lorsque des paramètres sont ajoutés. Il est impossible d'extraire le code SQL d'un PreparedStatement, car il utilise un formulaire binaire compilé.

LoggedPreparedStatement semble prometteur, même si je ne l’ai pas essayé.

Un des avantages de ceux-ci par rapport à un pilote proxy qui enregistre toutes les requêtes est que vous pouvez modifier la chaîne de requête avant de la consigner. Par exemple, dans un environnement PCI, vous pouvez masquer les numéros de carte.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top