2009-04-07 9 views
10

Ho un programma Java che è agnostico dal database e ho bisogno di sapere, durante l'inserimento, se è stata lanciata una SQLException a causa di una chiave duplicata.Trova se è stata generata una SQLException a causa di un duplicato

Se stavo usando un singolo driver di database, userei semplicemente l'ErrorCode, ma dato che posso usare motori molto diversi, gli ErrorCode non sono gli stessi.

Qualcuno ha già fatto questo? Qualche idea?

TIA Molti!

Edit: Ho un file di configurazione in cui devo conservare la classe di driver (ad esempio: org.apache.derby.jdbc.ClientDriver) e alcune altre informazioni necessarie (ad esempio: nome utente, password, URL ...). La connessione viene sempre passata come "java.SQL.Connection", quindi non mi interessa davvero quale driver viene utilizzato.

+0

Come stai accedendo ai dati nel codice? Stai passando per JDBC o hai classi specifiche del database? –

+0

Ho un file di configurazione in cui sono memorizzati i parametri di classe e connessione del driver. – ferro

risposta

7

Con JDBC di base, non c'è davvero un modo per fare ciò che si sta dicendo in modo cross-database. Come hai menzionato, è possibile utilizzare getErrorCode, ma sono richiesti i codici di errore specifici del fornitore.

Gli unici tre modi che vedo per aggirare questo è:

  1. utilizzare una sorta di cornice che fa tutto il traduzione dal codice di errore di eccezioni significative (Hibernate probabilmente fare questo, qualcun altro ha detto che La primavera funziona)
  2. Controllare manualmente il duplicato (con una selezione) prima di inserire il proprio inserto. (Questo non sarebbe del 100%, in quanto tecnicamente possibile che qualcuno avrebbe potuto fare un inserto dopo la tua query).
  3. Dopo aver ottenuto l'eccezione sql sull'inserto, provare a eseguire una query per quell'ID. Se riesci a trovare la corrispondenza, puoi essere abbastanza sicuro che l'errore che hai ricevuto è dovuto a una chiave primaria duplicata. (Anche se è possibile che ci siano stati più problemi, e che in realtà non era quello che è stato lanciato).

La mia raccomandazione sarebbe quella di scrivere il codice per evitare il problema il più possibile, e quindi (se assolutamente necessario), utilizzare # 3.

+0

# 3 non sembra un consiglio particolarmente valido perché ignora la concorrenza. Cioè, cosa succede se qualche altra connessione cancellato o aggiunto il record in questione, ma questa connessione ha gettato un'eccezione per un motivo estraneo completo? Non c'è modo per questa connessione di bloccare una riga che non c'è, quindi non può dimostrare che è quella. (Immagino che potrebbe bloccare l'intera tabella, ma minimizza l'accesso simultaneo al tavolo.) In realtà, quindi, # 2 e # 3 hanno gli stessi problemi di concorrenza; questo ci lascia con # 1 come l'unica opzione praticabile. – MikeB

0

Credo che un modo semplice e affidabile consiste nel verificare se la chiave esiste prima di eseguire l'inserimento. Come hai giustamente sottolineato, ogni database ha il proprio modo di segnalare l'errore.

+0

Dipende da come si accede ai dati nel codice. Questo non è chiaro dalla domanda, quindi sicuramente non direi che questo è il "solo" modo. –

+0

Non riesco a vedere come i dati a cui si accede nel codice influiranno su una chiave duplicata sull'inserto. Tuttavia non posso affermare che questa è l'unica soluzione. La mia risposta è stata modificata. – wentbackward

1

Bene, se non puoi contare sull'eccezione per dirti perché è stata generata, puoi eseguire il test seguendo l'eccezione con un "select count (*) dalla tabella dove key = @keyfailedtoinsert;"

Sfortunatamente, non è garantita l'eccezione per fornire il nome della tabella e il nome della chiave. In alcuni casi, il codice java che ha chiamato il driver JDBC potrebbe non averli mai avuti, ad es. Se l'inserto si è verificato con una procedura memorizzata o come in un trigger.

Quindi si sta tornando a dover fidarsi di ogni fornitore di driver JDBC.

2

È possibile "addestrare" il programma all'avvio (o configurazione) inserendo una chiave duplicata conosciuta e registrando il codice di errore generato.

+0

Ciò presuppone che l'errore restituito sia effettivamente la chiave duplicata sull'inserto. Non hai modo di dimostrare che l'errore era in realtà quello che ti aspettavi. – wentbackward

+0

@wentbackward - Puoi prendere il caso del 90% e supporre che sia giusto dopo aver effettuato la connessione, selezionare, testare, selezionare - e/o semplicemente chiedere all'utente di leggere il messaggio di errore e confermare. Non è una scienza esatta, ma è molto probabile che sia abbastanza vicina. –

0

Mi manca qualcosa? Se si utilizza JDBC, è necessario recuperare un'eccezione chiave duplicata, indipendentemente dal DB in uso.

Oppure hai chiesto come si determinerebbe un dupkey PRIMA di aver provato l'inserimento?

-1

Suppongo che non si stia utilizzando JDBC o questa sarebbe una semplice ricerca di errori.

Avete un diverso insieme di classi per accedere ai diversi database? In tal caso, è possibile rilevare l'eccezione nelle classi specifiche del database e generare il proprio tipo di eccezione condiviso da tutti i tipi di database.

2

Penso che la soluzione ideale sarebbe che il livello dati generi un'eccezione specifica in questo caso, forse una sottoclasse di SQLException per DuplicateKeyException o qualcosa di simile.

Se si desidera essere in grado di trattare diverse eccezioni in modo diverso, è necessario lanciare diversi tipi di eccezioni (o sottotipi) per iniziare.

Penso che questo è un settore in cui Spring Framework ottiene le cose veramente giusto: essi forniscono a very rich hierarchy of "database exceptions" tutti che si estendono DataAccessException, con sub-alberi di tipi per "eccezioni recuperabili", "eccezioni transitorie", "eccezioni di integrità dei dati" ecc. Questo lascia il codice cliente libero di catturare qualsiasi (o nessuno) dei tipi di eccezione che possa gestire o preoccupare: eccezioni che indicano un errore che potrebbe non essere ripetibile se si esegue nuovamente la transazione, un errore non fatale -errore irreversibile, oppure puoi semplicemente prendere il tipo di root.

8

Questo è esattamente ciò che SQLException.getSQLState() è per. Secondo Google, "23000" indica una violazione del vincolo univoco in almeno MySQL, PostgreSQL e Oracle.

+1

Ad esempio su DB2 non è lo stesso – ferro

+0

Hrm, hai ragione. Quanti database hai bisogno di supportare? È davvero un numero infinito? Potrebbe essere meglio capire quale sia la coppia SQLState/ErrorCode per ogni DB e gestirli tutti. Funzionerà ancora molto, molto meglio di un SELECT per controllare la fila prima del tempo. –

+0

Sto per creare un metodo che riceverà la connessione DB, per verificare quale driver viene utilizzato e l'eccezione, quindi confronterò getSQLState() e controllerò se è una chiave duplicata. – ferro

Problemi correlati