Domanda

Una cosa che è sempre stata una seccatura è registrare gli errori SQL (JDBC) quando si dispone di un PreparedStatement invece della query stessa.

Ti ritrovi sempre con messaggi come:

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

Ovviamente potrei scrivere un metodo di supporto per recuperare i valori e analizzare / sostituire i punti interrogativi con valori reali (e probabilmente seguirò quella strada se non ottengo un risultato di questa domanda), ma volevo solo per sapere se questo problema è stato risolto in precedenza da qualcun altro e / o se esiste un helper di registrazione generico che lo farebbe automaticamente per me.

Modificato dopo alcune risposte:

Le librerie fornite finora sembrano adatte a registrare le istruzioni per il debug, il che senza dubbio è utile. Tuttavia, sto cercando un modo per prendere un PreparedStatement stesso (non una sottoclasse) e registrare la sua istruzione SQL ogni volta che si verifica un errore. Non vorrei distribuire un'app di produzione con un'implementazione alternativa di PreparedStatement.

Suppongo che sto cercando una classe di utilità, non una specializzazione PreparedStatement.

Grazie!

È stato utile?

Soluzione

Ho provato log4jdbc e ha funzionato per me.

NOTA DI SICUREZZA: a partire da oggi agosto 2011, i risultati registrati di un'istruzione preparata log4jdbc NON SONO SICURI da eseguire. Possono essere utilizzati per l'analisi, ma non devono MAI essere reimmessi in un DBMS.

Esempio del registro generato da logjdbc:

  

2010/08/12 16:30:56 jdbc.sqlonly   org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate (DelegatingPreparedStatement.java:105)   8. INSERIRE IN A_TABLE   (ID_FILE, CODE1, ID_G, ID_SEQUENCE, REF, NAME, BAR, DRINK_ID, importo, descrizione, stato, CODE2, REJECT_DESCR, ID_CUST_REJ)   VALORI   (2, '123', 1, '2', 'aa', 'timore', null, '0123', 4317,95, 'RCCC', '0', null, null)

La libreria è molto facile da configurare:


La mia configurazione con HSQLDB :

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

Con Oracle :

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

logback.xml:

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

Peccato che non fosse su un repository maven, ma comunque utile.
Da quello che ho provato, se hai impostato

Riceverai solo le dichiarazioni in errore, tuttavia, non so se questa libreria ha un impatto sulle prestazioni.

Altri suggerimenti

Questo dipende molto dal database. Ad esempio, capisco che alcuni driver JDBC (ad esempio sybase, forse ms-sql) gestiscono le istruzioni preparate creando una procedura temporanea memorizzata sul server e quindi invocando tale procedura con gli argomenti forniti. Quindi l'SQL completo non viene mai effettivamente passato dal client.

Di conseguenza, l'API JDBC non espone le informazioni che stai cercando. Potresti essere in grado di trasmettere i tuoi oggetti statement all'implementazione del driver interno, ma probabilmente no - il tuo server di app potrebbe avvolgere le istruzioni nella propria implementazione.

Penso che potresti dover solo mordere il proiettile e scrivere la tua classe che interpola gli argomenti nel segnaposto SQL. Questo sarà imbarazzante, perché non puoi chiedere a PreparedStatement i parametri che sono stati impostati, quindi dovrai ricordarli in un oggetto helper, prima di passarli all'istruzione.

Mi sembra che una delle librerie di utilità che avvolgono gli oggetti di implementazione del driver sia il modo più pratico di fare ciò che stai cercando di ottenere, ma sarà sgradevole in entrambi i casi.

Usa P6Spy : Oracle, Mysql, JNDI, JMX, Primavera e Maven amichevoli. Altamente configurabile Integrazione semplice e di basso livello Può stampare il stacktrace . Può solo stampare chiamate pesanti - in base al limite temporale.

  1. Se si utilizza MySQL, PreparedStatement.toString () utilizza MySQL include i parametri associati . Sebbene i pool di connessione di terze parti possano interrompere questo.

  2. Sottoclasse PreparedStatement per creare la stringa di query man mano che vengono aggiunti i parametri. Non è possibile estrarre l'SQL da un PreparedStatement, poiché utilizza un modulo binario compilato.

LoggedPreparedStatement sembra promettente, anche se non l'ho provato.

Un vantaggio di questi rispetto a un driver proxy che registra tutte le query è che è possibile modificare la stringa di query prima di registrarla. Ad esempio in un ambiente PCI potresti voler mascherare i numeri delle carte.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top