2013-04-20 12 views
6

Oto kod, który działa:Pobieranie id seryjny z partii wstawiony wierszy w 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(); 
     } 

Ale teraz muszę wypełnić inną tabelę gdzie id jest kluczem obcym. Jeśli używam INSERT z RETURNING id, wówczas executeBatch kończy się niepowodzeniem z komunikatem "Wynik został zwrócony, gdy nie był oczekiwany".

widzę kilka sposobów rozwiązania tego

  • Czy indywidualną wkładkę zamiast wkładki partii.
  • Zamień identyfikator seryjny na identyfikator wygenerowany przez klienta.
  • Użyj jakiejś procedury przechowywanej, aby wstawić wsad i wyświetlić listę identyfikatorów.

z trzech metod, które widzę ten ostatni wydaje się zachować zarówno skuteczność wkładki wsadowym i powrócić identyfikatory, ale jest to także najbardziej skomplikowane dla mnie, nigdy nie pisałem procedur przechowywanych.

Czy istnieje lepszy sposób wstawienia partii i uzyskania identyfikatorów? Nie mam problemu z używaniem specyficznego API PostgreSQL zamiast jdbc.

Jeśli nie, czy ktokolwiek mógłby szkicować taką procedurę przechowywaną?

Oto schemat tabela:

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

Spójrz na metody JDBC 'getGeneratedKeys'. Jednak nie weryfikowaliśmy tego specjalnie dla połączeń wsadowych. –

+0

Co powiesz na zapełnianie obu tabel jednocześnie za pomocą WCTE? –

+0

@JakubKania - co to jest WCTE? Czy możesz pokazać przykład? – mark

Odpowiedz

10

Coś jak to powinno działać:

// 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 
} 

myślę (! Jestem nie pewien), że klucze są zwracane w kolejności ich zostały wygenerowane. Zatem pierwszy wiersz z ResultSet powinien być odwzorowany na pierwszy "element" z przetwarzanej listy. Ale sprawdź to!

Edit

Jeśli to nie zadziała, spróbuj określenie rzeczywistych kolumn, dla których wartości są generowane:

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

To nie działa - zwrócony zestaw wyników jest pusty. – mark

+0

@mark: musisz poinformować kierowcę, aby zwrócił te wartości podczas przygotowywania instrukcji. Zobacz moją edycję. –

+1

OK, to działa. Ale coś zostało. Nie masz pewności, czy pierwszy wiersz odwzorowuje pierwszy zwrócony identyfikator. Dokumentacja na http://docs.oracle.com/javase/1.4.2/docs/guide/jdbc/getstart/preparedstatement.html nic o tym nie mówi. Jest to jednak bardzo ważna informacja. Bez tej gwarancji funkcja jest bezużyteczna. Czy jest to gwarantowane, przynajmniej dla postgresql? – mark

Powiązane problemy