Sto lavorando con JDBC e HSQLDB 2.2.9. Qual è il modo più efficiente ed accurato per inserire una nuova riga in un DB e, successivamente, mantenere il suo valore id
(PK set to autoincrement)? La ragione per cui ho bisogno di fare questo è probabilmente abbastanza ovvio, ma io illustrare con un esempio per la discussione:Come recuperare il valore dell'ID PK precedentemente generato automaticamente utilizzando JDBC e HSQLDB
dire che c'è un tavolo Customer
che ha un campo PersonId
con un vincolo FK riferimento ad una riga da una tabella Person
. Voglio creare un nuovo Customer
, ma per fare questo ho bisogno di creare prima un nuovo Person
e utilizzare il nuovo valore Person.id
per impostare Customer.PersonId
.
Ho visto quattro modi per affrontare questo:
inserire impostando il campo
id
alnull
rigaPerson
. HSQLDB genera automaticamente il prossimo valoreid
. Quindi eseguire una query sulla tabellaPerson
per ottenere il valoreid
appena creato e utilizzarlo per creare la nuova rigaCustomer
.Questo sembra costoso solo per recuperare un singolo valore intero.
Prendi il
id
valore successivo nella tabellaPerson
e utilizzarlo nella dichiarazioneINSERT
per impostare manualmente il valorePerson.id
. Utilizzare lo stesso valoreid
per impostareCustomer.PersonId
. Non è necessaria alcuna lettura successiva dal DB.incongruenze potrebbero sorgere se si ottiene un valore
id
, ma un altro collegamento compie unINSERT
nella tabella prima che venga eseguita la miaINSERT INTO Person...
dichiarazione.Eseguire la dichiarazione
INSERT
, come nell'opzione 1 sopra, impostandoid=null
per consentire la generazione automatica. Quindi utilizzare il metodogetGeneratedKeys
per recuperare le chiavi generate nell'ultima istruzione.Ho pensato che fosse una buona opzione, ma non riuscivo a farlo funzionare. Ecco un frammento del mio codice:
// PreparedStatement prepared previously... preparedStatement.executeUpdate(); ResultSet genKeys = preparedStatement.getGeneratedKeys(); int id; if (genKeys.next()) { id = genKeys.getInt(1); } // Finish up method...
Questo codice è stato restituisce un vuoto
ResultSet
pergenKeys
. Sto usando il metodogetGeneratedKeys
in modo errato? Se potessi farlo funzionare, questa potrebbe essere la strada da percorrere.Anche in questo caso, eseguire la dichiarazione
INSERT
che consente di generare automaticamenteid
. Quindi eseguire immediatamenteCALL IDENTITY()
per recuperare l'ultimo valoreid
generato dalla connessione (come spiegato here e menzionato nella domanda SO this).Anche questa sembra un'opzione ragionevole, anche se devo eseguire un ulteriore
executeQuery
. Sul lato positivo, mi è stato effettivamente in grado di farlo funzionare con il seguente codice:// INSERT statement executed here... statement = connection.createStatement(); ResultSet rs = statement.executeQuery("CALL IDENTITY();"); int id; if (rs.next()) id = rs.getInt(1); // Finish up method...
Così, in sintesi, le prime due opzioni non sono pazzo circa.I secondi due sembrano ok, ma ho potuto solo ottenere l'opzione 4 per funzionare. Quale opzione è preferita e perché? Se l'opzione 3 è la migliore, cosa sto sbagliando? Inoltre, c'è un modo migliore che non ho menzionato? So che parole come "migliori" possono essere soggettive, ma sto lavorando con un semplice DB e voglio la soluzione più diretta che non apre il DB a possibili incoerenze e non aumenta il tasso di errore della transazione (a causa del tentativo per creare un record con uno id
già esistente).
Questa sembra una domanda di base (ed essenziale), ma non ho trovato molte indicazioni sul modo migliore per farlo. Grazie.
EDIT: Ho appena trovato this domanda che discute la mia opzione 3. Secondo la risposta accettata, sembra stavo lasciando fuori il parametro
Statement.RETURN_GENERATED_KEYS
necessario per consentire tale funzionalità. Non ho mostrato il metodo
prepareStatement
nel mio snippet di codice, ma stavo usando la versione a parametro singolo. Ho bisogno di riprovare usando la versione sovraccaricata, a due parametri.
Ci sono anche alcune altre domande SO che si presentano con quella domanda che sono strettamente correlate alla mia domanda. Quindi, immagino che il mio possa essere considerato un duplicato (non sono sicuro di aver perso prima queste altre domande). Ma mi piacerebbe ancora qualche indicazione su se una soluzione è considerata migliore delle altre. Per ora, se riesco a far funzionare l'opzione 3, probabilmente ci andrò.
Per essere onesti, Io non vedo perché che significa meno bastone alla soluzione No1. Fare una SELECT sull'ID della riga appena inserita ha il solito sovraccarico di una query, ma poi di nuovo, anche tutte le altre opzioni. –
Non sarei 'SELECT'ing su' id', ma piuttosto su una serie di altri campi che comprendono un'altra chiave univoca. Il valore 'id' sarebbe quello che sto cercando. Ma il tuo commento sul "solito sovraccarico di una query" continua a essere valido indipendentemente dai dettagli della query. Tuttavia, non ero sicuro del sovraccarico previsto nell'opzione 3. Ho pensato che le informazioni sarebbero rimaste dall'esecuzione della dichiarazione precedente. Per l'opzione 4 non ero sicuro se l'esecuzione di una query di "CALL IDENTITY()" fosse più economica di una "SELECT" regolare "SELECT". – neizan
Non so se lo è, neanche. Personalmente, non mi preoccuperei di una sola query dopo un inserto, ma naturalmente non conosco le specifiche del tuo compito. –