2010-07-02 20 views
14

W jaki sposób można wykonać następujące SQL w skalowalny sposób przy użyciu JdbcTemplate działającego na mySQL. W tym przypadku, skalowalnych środki:Wstawianie wielu wierszy przy użyciu JdbcTemplate

  1. oświadczenie Tylko jedna SQL jest wykonywany na serwerze
  2. działa dla dowolnej liczby wierszy.

Oto zestawienie:

INSERT INTO myTable (foo, bar) VALUES ("asdf", "asdf"), ("qwer", "qwer") 

Załóżmy, że mam listę POJO jest z foo i bar dziedzinach. Zdaję sobie sprawę, że może po prostu iteracyjne nad listy i wykonanie:

jdbcTemplate.update("INSERT INTO myTable(foo, bar) VALUES (?, ?)", paramMap) 

ale to nie nie osiągnąć pierwsze kryterium.

wierzę mogę również wykonać:

jdbcTemplate.batchUpdate("INSERT INTO myTable(foo, bar) VALUES (?, ?)", paramMapArray) 

ale z tego co mogę powiedzieć, że będzie po prostu skompilować SQL raz i wykonać go wielokrotnie, kolejny nie pierwsze kryterium.

Ostatnią możliwością, która zdaje się spełniać oba kryteria, byłoby samodzielne zbudowanie kodu SQL przy pomocy StringBuffer, ale chciałbym tego uniknąć.

+0

Możemy zrobić to samo przy użyciu tylko JDBC? ? –

+0

Nie ma to nic wspólnego z JdbcTemplate, a nawet z JDBC. Nie możesz tego zrobić w SQL, kropce (lub standardowym SQL, tak czy inaczej), więc na pewno nie możesz tego zrobić w JdbcTemplate. – skaffman

+0

@skaffman: Zaktualizowałem moje pytanie, aby powiedzieć, że używam mySQL. Być może jest to funkcja tylko dla MySQL, ale jest opisana na stronie http://dev.mysql.com/doc/refman/5.1/en/insert.html na temat jednej czwartej drogi do dołu: "INSERT, które używają składni VALUES mogą wstawiać Aby to zrobić, dołącz wiele list wartości kolumn, każda ujęta w nawiasy i oddzielona przecinkami Przykład: " –

Odpowiedz

4

Wstawki wielowierszowe (używając "konstruktorów wartości rzędów") są w rzeczywistości częścią standardu SQL-92. Zobacz http://en.wikipedia.org/wiki/Insert_(SQL)#Multirow_inserts.

Niektóre bazy danych nie obsługują tej składni, ale wiele z nich robi. Z mojego doświadczenia wynika, że ​​wspierają to Derby/Cloudscape, DB2, Postgresql i nowsze wersje Hypersonic 2. * +.

Twoja troska o to, aby to działało jako Przygotowane Stanowisko jest zrozumiała, ale widziałem podobne przypadki, w których Spring JDBC automatycznie obsługuje kolekcję przedmiotów dla pewnych zapytań (np. Gdzie w (?)), Ale nie mogę ręczyć w tym przypadku.

Znalazłem możliwie pomocne informacje na (nie mogę dodać drugiego linku do tego postu) , które mogą być pomocne.

Mogę powiedzieć, że prawdopodobnie nie jest możliwe spełnienie drugiego wymogu (działa dla dowolnej liczby argumentów) w najbardziej ścisłym tego słowa znaczeniu: każda używana przeze mnie baza danych nakłada ograniczenia długości kwerend, które wchodzą w grę .

+0

adres URL, który SO nie zezwala na umieszczanie powyżej, to: http://fusesource.com/docs/router/2.2/transactions/DataAccess-JDBC.html – Will

-4

Nie można tego zrobić w JDBC, kropka. W MySQL jest to po prostu cukier syntaktyczny, ale efekt instrukcji będzie taki sam, jak wydanie kilku instrukcji INSERT. Więc możesz użyć batchUpdate i będzie to miało ten sam efekt.

+1

Niepoprawnie. "Rozszerzona wstawka" MySQL (przedstawiona w pytaniu) jest szybsza niż wstawka wsadowa (gdzie przygotowujesz z wyprzedzeniem, ale wstawiasz jeden wiersz na raz). To nie jest syntaktyczny cukier w MySQL. –

28

Możesz użyć BatchPreparedStatementSetter jak poniżej.

public void insertListOfPojos(final List<MyPojo> myPojoList) { 

    String sql = "INSERT INTO " 
     + "MY_TABLE " 
     + "(FIELD_1,FIELD_2,FIELD_3) " 
     + "VALUES " + "(?,?,?)"; 

    getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() { 

     @Override 
     public void setValues(PreparedStatement ps, int i) 
      throws SQLException { 

      MyPojo myPojo = myPojoList.get(i); 
      ps.setString(1, myPojo.getField1()); 
      ps.setString(2, myPojo.getField2()); 
      ps.setString(3, myPojo.getField3()); 

     } 

     @Override 
     public int getBatchSize() { 
      return myPojoList.size(); 
     } 
    }); 

} 
+0

Mam "Indeks parametru poza zakresem (1> numer parametrów, co oznacza 0) "podczas używania: NamedParameters zamiast?. Trochę aktualizacji do używania z NamedParameterJdbcTemplate? – luso

-1

Możesz także spróbować z jdbcInsert.executeBatch (sqlParamSourceArray)

// define parameters 
jdbcInsert = new SimpleJdbcInsert(jdbcTemplate); 
jdbcInsert.withTableName("TABlE_NAME"); 
SqlParameterSource[] sqlParamSourceArray = new SqlParameterSource[apiConsumer 
     .getApiRoleIds().size()]; 
for (int i = 0; i < myCollection.size(); i++) 
    { 
    sqlParamSourceArray[i] = new MapSqlParameterSource().addValue("COL1"); 
     ...................... 
} 
// execute insert 
int[] keys = jdbcInsert.executeBatch(sqlParamSourceArray); 
+0

Ta odpowiedź jest nieprawdziwa! 'jdbcInsert.executeBatch()' NIE zwraca kluczy. Zwraca 'tablicę liczby wierszy, których dotyczy, zwróconych przez sterownik JDBC'. Zobacz javadocs. https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/simple/SimpleJdbcInsert.html#executeBatch-org.springframework.jdbc.core.namedparam.SqlParameterSource – Stewart

0

Wydaje mi się, że() metoda batchUpdate z JdbcTemplate mogłyby być pomocne w tym przypadku (skopiowane stąd):

//insert batch example 
public void insertBatch(final List<Customer> customers){ 

    String sql = "INSERT INTO CUSTOMER " + 
    "(CUST_ID, NAME, AGE) VALUES (?, ?, ?)"; 

    getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() { 

@Override 
public void setValues(PreparedStatement ps, int i) throws SQLException { 
    Customer customer = customers.get(i); 
    ps.setLong(1, customer.getCustId()); 
    ps.setString(2, customer.getName()); 
    ps.setInt(3, customer.getAge()); 
} 

@Override 
public int getBatchSize() { 
    return customers.size(); 
} 

    }); 
} 
Powiązane problemy