2009-06-16 8 views
9

C'è un modo per inserire una riga in una tabella e ottenere il nuovo ID generato, in una sola istruzione? Voglio usare JDBC e l'ID sarà generato da una sequenza o sarà un campo di autoincremento.Ottenere l'ID di un inserto nella stessa istruzione

Grazie per il vostro aiuto.

John Pollancre

+0

Può fare un esempio di ciò che si vuole fare, ammesso che fosse possibile ? – skaffman

+0

Ovviamente. Considera la tabella void A (id [autoincrement], campo). Vorrei qualcosa del tipo: long id = jdbcStatement.execute ("inserisci in valori A (campo) ('blah')"); o long id = jdbcStatement.execute ("inserire in valori A (id, campo) (sequence.nextval, 'blah')"); Voglio id = 1, e tutto fatto in un solo accesso al DB –

+0

+1 Buona domanda e utile quando si inseriscono oggetti che sono collegati sul lato di Java. –

risposta

0

Il valore del ID generato automaticamente non è noto fino a dopo l'INSERT viene eseguita, perché altre dichiarazioni potrebbero essere in esecuzione contemporaneamente e RDBMS arriva a decidere come programmare quale inizia per primo.

Qualsiasi funzione chiamata in un'espressione nell'istruzione INSERT deve essere valutata prima dell'inserimento della nuova riga e quindi non può sapere quale valore ID viene generato.

posso pensare a due opzioni che sono vicino a quello che stai chiedendo:

  • Scrivi un trigger che viene eseguito dopo l'inserimento, in modo da avere accesso al valore chiave ID generato.

  • Scrivere una procedura per avvolgere l'inserto, in modo da poter eseguire altro codice nella procedura e interrogare l'ultimo ID generato.

Tuttavia, ho il sospetto quello che stai realmente chiedendo è se è possibile interrogare per l'ultimo valore ID generato dalla vostra sessione corrente anche se altre sessioni sono anche l'inserimento di righe e di generare i propri valori ID. Si può essere certi che ogni RDBMS che offre una funzione di incremento automatico offre un modo per interrogare questo valore e indica l'ultimo ID generato nell'ambito della sessione corrente. Questo non è influenzato dagli inserimenti eseguiti in altre sessioni.

+0

"... perché altre istruzioni potrebbero essere eseguite simultaneamente ..." Mi stavo chiedendo. Che ne dici di sincronizzare i metodi in Java per impedirlo? –

+0

È possibile serializzare le transazioni stabilendo sezioni critiche nel codice dell'applicazione o richiedendo esplicitamente blocchi di tabelle, ma il fatto rimane che SQL non ha alcuna sintassi per richiedere l'id nella stessa istruzione. –

10

utilizzando getGeneratedKeys():

resultSet = pstmt.getGeneratedKeys(); 

if (resultSet != null && resultSet.next()) { 
    lastId = resultSet.getInt(1); 
} 
+0

Fantastico! Non ne ho mai sentito! Pensi che funzioni con gli ID generati da una sequenza? Grazie, dfa! –

+0

basta provarlo :-) – dfa

+1

I driver JDBC Oracle restituiscono il ROWID per getGeneratedKeys, perché Oracle non ha il concetto effettivo di una chiave generata automaticamente - ha sequenze, ma devi esplicitamente usarle per popolare il campo nel tuo INSERT o in un trigger. Vorrei usare il metodo RETURNING descritto da Vincent. –

0

l'ID generato da una sequenza può essere ottenuta tramite

insert into table values (sequence.NextVal, otherval) 
select sequence.CurrVal 

corse nella stessa transazione da ottenere una visione coerente.

+0

Questo thread non è sicuro come indicato da Robert M. di seguito. – massfords

6

È possibile utilizzare la clausola RETURNING per ottenere il valore di qualsiasi colonna in cui è stato aggiornato o inserito. Funziona con il trigger (i-e: ottieni i valori effettivamente inseriti dopo l'esecuzione dei trigger). Considerate:

SQL> CREATE TABLE a (ID NUMBER PRIMARY KEY); 

Table created 
SQL> CREATE SEQUENCE a_seq; 

Sequence created 
SQL> VARIABLE x NUMBER; 
SQL> BEGIN 
    2  INSERT INTO a VALUES (a_seq.nextval) RETURNING ID INTO :x; 
    3 END; 
    4/

PL/SQL procedure successfully completed 
x 
--------- 
1 

SQL>/

PL/SQL procedure successfully completed 
x 
--------- 
2 
0

penso che troverete questo utile:

Ho una tabella con un id incremento automatico . Da ora a volta voglio inserire le righe su questa tabella , ma voglio essere in grado di sapere quello che il pk della riga appena inserita è .

String query = "BEGIN INSERT INTO movement (doc_number) VALUES ('abc') RETURNING id INTO ?; END;"; 
OracleCallableStatement cs = (OracleCallableStatement) conn.prepareCall(query); 
cs.registerOutParameter(1, OracleTypes.NUMBER); 
cs.execute(); 
System.out.println(cs.getInt(1)); 

Fonte

: Thread: Oracle/JDBC Error when Returning values from an Insert

0

non ho potuto commentare, altrimenti avrei appena aggiunto al post di DFA, ma il seguente è un esempio di questa funzionalità con JDBC dritto.

http://www.ibm.com/developerworks/java/library/j-jdbcnew/

Tuttavia, se si utilizza qualcosa come la primavera, saranno mascherare un sacco di dettagli scabrosi per voi. Se questo può essere di qualche aiuto, basta il buon Capitolo 11, che è il dettaglio JDBC. Usarlo mi ha risparmiato un sacco di mal di testa.

1

non potevo lasciare un commento, altrimenti avrei aggiunto al post di Vinko Vrsalovic:

The id generated by a sequence can be obtained via 

insert into table values (sequence.NextVal, otherval) 
select sequence.CurrVal 

ran in the same transaction as to get a consistent view. 

Aggiornamento de sequenza dopo aver ottenuto un nextval da esso è una transazione autonoma. Altrimenti un'altra sessione otterrebbe lo stesso valore dalla sequenza. Quindi ottenere currval non otterrà l'id inserito se la sessessione è stata selezionata dalla sequenza tra l'inserimento e la selezione.

saluti, Rob

+0

E riguardo le transazioni nidificate? (Non è un esperto di Oracle, quindi scusate le domande stupide) –

3

In realtà, credo nextval seguito da currval funziona. Ecco un po 'di codice che simula questo comportamento con due thread, uno che prima fa un nextval, quindi un currval, mentre un secondo thread fa un nextval in mezzo.

public void checkSequencePerSession() throws Exception { 
    final Object semaphore = new Object(); 
    Runnable thread1 = new Runnable() { 
     public void run() { 
      try { 
       Connection con = getConnection(); 
       Statement s = con.createStatement(); 
       ResultSet r = s.executeQuery("SELECT SEQ_INV_BATCH_DWNLD.nextval AS val FROM DUAL "); 
       r.next(); 
       System.out.println("Session1 nextval is: " + r.getLong("val")); 
       synchronized(semaphore){ 
       semaphore.notify(); 
       } 
       synchronized(semaphore){ 
       semaphore.wait(); 
       } 
       r = s.executeQuery("SELECT SEQ_INV_BATCH_DWNLD.currval AS val FROM DUAL "); 
       r.next(); 
       System.out.println("Session1 currval is: " + r.getLong("val")); 
       con.commit(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }; 
    Runnable thread2 = new Runnable(){ 
     public void run(){ 
      try{ 
       synchronized(semaphore){ 
       semaphore.wait(); 
       } 
       Connection con = getConnection(); 
       Statement s = con.createStatement(); 
       ResultSet r = s.executeQuery("SELECT SEQ_INV_BATCH_DWNLD.nextval AS val FROM DUAL "); 
       r.next(); 
       System.out.println("Session2 nextval is: " + r.getLong("val")); 
       con.commit(); 
       synchronized(semaphore){ 
       semaphore.notify(); 
       } 
      }catch(Exception e){ 
       e.printStackTrace(); 
      } 
     } 
    }; 
    Thread t1 = new Thread(thread1); 
    Thread t2 = new Thread(thread2); 
    t1.start(); 
    t2.start(); 
    t1.join(); 
    t2.join(); 
} 

Il risultato è il seguente: Session1 nextval è: 47 Sessione 2 nextval è: 48 Session1 currval è: 47

Problemi correlati