2013-04-20 8 views
6

Ecco il codice che funziona:Recupero ID seriale da lotto inserito righe in PostgreSQL

 Connection c = ds.getConnection(); 
     c.setAutoCommit(false); 
     PreparedStatement stmt = c.prepareStatement("INSERT INTO items (name, description) VALUES(?, ?)"); 
     while (!(items = bus.take()).isEmpty()) { 
      for (Item item : items) { 
      stmt.setString(1, item.name); 
      stmt.setString(2, item.description); 
      stmt.addBatch(); 
      } 
      stmt.executeBatch(); 
      c.commit(); 
     } 

Ma ora ho bisogno di compilare un altro tavolo dove id è una chiave esterna. Se utilizzo INSERT con RETURNING id, il executeBatch non riesce con errore "È stato restituito un risultato quando nessuno era previsto".

vedo diversi modi per risolvere questo

  • fare inserto individuale piuttosto che l'inserto in batch.
  • Sostituisci ID seriale con guid generato dal client.
  • Utilizzare una sorta di stored procedure per eseguire l'inserimento batch e restituire un elenco di ID.

dei tre metodi che vedo l'ultimo sembra preservare sia l'efficienza del inserto in batch e restituire gli ID, ma è anche il più complesso per me, come ho mai scritto stored procedure.

C'è un modo migliore per inserire in batch e ottenere gli ID? Non ho problemi ad usare API postgresql piuttosto che jdbc.

In caso contrario, si può abbozzare una tale procedura memorizzata?

Ecco lo schema della tabella:

CREATE UNLOGGED TABLE items 
(
    id serial, 
    name character varying(1000), 
    description character varying(10000) 
) 
WITH (
    OIDS=FALSE 
); 
+0

Date un'occhiata al metodo di JDBC 'getGeneratedKeys'. Non l'ho verificato specificamente per le connessioni batch, però. –

+0

Che ne dici di popolare entrambe le tabelle contemporaneamente con wCTE? –

+0

@JakubKania - Che cos'è wCTE? Puoi mostrare un esempio? – mark

risposta

10

Qualcosa del genere dovrebbe funzionare:

// tell the driver you want the generated keys 
stmt = c.prepareStatement("INSERT ... ", Statement.RETURN_GENERATED_KEYS); 

stmt.executeBatch(); 

// now retrieve the generated keys 
ResultSet rs = stmt.getGeneratedKeys(); 
while (rs.next()) { 
int id = rs.getInt(1); 
.. save the id somewhere or update the items list 
} 

penso (! Sono non sicuro) che le chiavi vengono restituiti nell'ordine in cui sono sono stati generati. Quindi la prima riga dal ResultSet dovrebbe mappare sul primo "elemento" dall'elenco che si sta elaborando. Ma verificalo!

Modifica

Se questo non funziona, provare a specificare le colonne effettive per cui vengono generati i valori:

stmt = c.prepareStatement("INSERT ... ", new String[] {"id"}); 
+0

Questo non funziona: il set di risultati restituito è vuoto. – mark

+0

@mark: è necessario indicare all'autista di restituire tali valori quando si prepara la dichiarazione. Vedi la mia modifica. –

+1

OK, funziona. Ma qualcosa è rimasto. Non sei sicuro che la prima riga sia mappata al primo ID restituito. La documentazione su http://docs.oracle.com/javase/1.4.2/docs/guide/jdbc/getstart/preparedstatement.html non dice nulla anche su questo. Tuttavia, questa è un'informazione cruciale. Senza questa garanzia la funzionalità è inutile. È garantito, almeno per postgresql? – mark