2010-07-02 50 views
14

¿Cómo puedo ejecutar el siguiente SQL de forma escalable usando JdbcTemplate ejecutándose en mySQL. En este caso, los medios escalables:Insertar varias filas usando JdbcTemplate

  1. Sólo una declaración SQL se ejecuta en el servidor
  2. funciona para cualquier número de filas.

Aquí está la declaración:

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

Supongamos que tengo una lista de POJO de foo con bar y campos. Soy consciente de que solo yo podría iterar sobre la lista y ejecutar:

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

pero eso no significa no cumple con el primer criterio.

creo que yo también podría ejecutar:

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

pero por lo que puedo decir, que se acaba de compilar el SQL de una vez y ejecutarlo varias veces, en su defecto el primer criterio de nuevo.

La última posibilidad, que parece superar ambos criterios, sería simplemente construir el SQL yo mismo con un StringBuffer, pero me gustaría evitar eso.

+0

¿Podemos hacer lo mismo usando sólo JDBC? ? –

+0

Esto no tiene nada que ver con JdbcTemplate, o incluso con JDBC. No puede hacer esto en SQL, punto (o SQL estándar, de todos modos), por lo que ciertamente no puede hacerlo en JdbcTemplate. – skaffman

+0

@skaffman: He actualizado mi pregunta para decir que estoy usando mySQL. Tal vez es una función mySQL-only, pero se describe en http://dev.mysql.com/doc/refman/5.1/en/insert.html aproximadamente un cuarto del camino hacia abajo: "Las instrucciones INSERT que usan la sintaxis VALUES pueden insertarse Para hacer esto, incluya varias listas de valores de columna, cada uno entre paréntesis y separados por comas. Ejemplo: " –

Respuesta

4

Las inserciones de Multirow (que usan "constructores de valores de fila") son de hecho parte del estándar SQL-92. Ver http://en.wikipedia.org/wiki/Insert_(SQL)#Multirow_inserts.

Algunas bases de datos no son compatibles con esta sintaxis, pero muchas sí. En mi experiencia, Derby/Cloudscape, DB2, Postgresql y las versiones más nuevas de Hypersonic 2. * + Sí lo admiten.

Su preocupación por hacer que esto funcione como un estado preparado es comprensible, pero he visto casos similares en los que Spring JDBC maneja automáticamente una colección de elementos para ciertas consultas (como dónde en (?)), Pero no puedo responder para este caso.

Encontré información posiblemente útil en (no puedo agregar un segundo enlace a esta publicación) que podría ser de alguna ayuda.

Puedo decirle que probablemente no sea posible cumplir con su segundo requisito (funciona para cualquier cantidad de argumentos) en el sentido más estricto: cada base de datos que he usado impone limitaciones de longitud de consulta que entrarían en juego .

+0

esa URL que SO no permitió que publicara anteriormente fue: http://fusesource.com/docs/router/2.2/transactions/DataAccess-JDBC.html – Will

-4

No puede hacer esto en JDBC, punto. En MySQL solo se trata de azúcar sintáctica, pero el efecto de la declaración será el mismo que emitir varias instrucciones INSERT. Entonces puedes usar batchUpdate y tendrá el mismo efecto.

+1

Incorrecto. La "inserción extendida" de MySQL (tal como se presenta en la Pregunta) es más rápida que una inserción por lotes (donde se prepara con anticipación pero se inserta una fila a la vez). NO es un azúcar sintáctico en MySQL. –

28

Puede usar BatchPreparedStatementSetter como a continuación.

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

Tengo "Índice de parámetros fuera de rango (1> número de parámetros, que es 0) "cuando se usa: NamedParameters en lugar de?. Alguna actualización para usar con NamedParameterJdbcTemplate? – luso

-1

también puedes probar con 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

¡Esta respuesta es falsa! 'jdbcInsert.executeBatch()' NO devuelve las claves. Devuelve 'la matriz de número de filas afectadas según lo devuelto por el controlador JDBC'. Ver los 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

A mi me parece que batchUpdate() método de JdbcTemplate podría ser útil en este caso (copiado de aquí):

//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(); 
} 

    }); 
} 
Cuestiones relacionadas