Вставка нескольких строк с помощью JdbcTemplate
Как я могу выполнить следующий SQL масштабируемым способом, используя JdbcTemplate, работающий на mySQL. В этом случае масштабируемые средства:
- На сервере выполняется только один оператор SQL
- он работает для любого количества строк.
Здесь утверждение:
INSERT INTO myTable (foo, bar) VALUES ("asdf", "asdf"), ("qwer", "qwer")
Предположим, что у меня есть список POJO с полями foo
и bar
. Я понимаю, что я мог просто перебирать список и выполнять:
jdbcTemplate.update("INSERT INTO myTable(foo, bar) VALUES (?, ?)", paramMap)
но это не выполняет первый критерий.
Я тоже могу выполнить:
jdbcTemplate.batchUpdate("INSERT INTO myTable(foo, bar) VALUES (?, ?)", paramMapArray)
но из того, что я могу сказать, будет просто компилировать SQL один раз и выполнить его несколько раз, не получив первый критерий снова.
Последняя возможность, которая, кажется, проходит оба критерия, состояла бы в том, чтобы просто построить SQL сам с StringBuffer
, но я бы хотел этого избежать.
Ответы
Ответ 1
Многострочные вставки (с использованием конструкторов значений строк) на самом деле являются частью стандарта SQL-92. Видеть
http://en.wikipedia.org/wiki/Insert_(SQL)#Multirow_inserts.
Некоторые базы данных не поддерживают этот синтаксис, но многие это делают. По моему опыту, Derby/Cloudscape, DB2, Postgresql и более новые версии Hypersonic 2. * + Поддерживают это.
Ваша озабоченность по поводу того, что это работает как PreparedStatement, понятна, но я видел похожие случаи, когда Spring JDBC автоматически обрабатывает коллекцию элементов для определенных запросов (например, где в (?)), но я не могу ручаться за этот случай.
Я нашел полезную информацию (не могу добавить вторую ссылку на этот пост)
что может оказать некоторую помощь.
Я могу сказать вам, что его, вероятно, невозможно для вашего второго требования (работает для любого количества аргументов) в наиболее строгом смысле: каждая используемая мной база данных налагает ограничения длины запросов, которые будут входить в игру.
Ответ 2
Вы можете использовать BatchPreparedStatementSetter, как показано ниже.
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();
}
});
}
Ответ 3
Мне кажется, что метод batchUpdate() JdbcTemplate может быть полезен в этом случае (скопировано здесь http://www.mkyong.com/spring/spring-jdbctemplate-batchupdate-example/):
//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();
}
});
}
Ответ 4
вы также можете попробовать с помощью 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);
Ответ 5
Вы не можете сделать это в JDBC, период. В MySQL это просто синтаксический сахар, но эффект от оператора будет таким же, как выдача нескольких инструкций INSERT. Таким образом, вы можете использовать batchUpdate, и он будет иметь тот же эффект.