2010-05-12 21 views
7

Estoy usando Spring's NamedParameterJdbcTemplate para realizar una inserción en una tabla. La tabla usa un NEXTVAL en una secuencia para obtener la clave primaria. Entonces quiero que me pasen esta ID generada. Estoy utilizando la aplicación de llaves de primavera de la siguiente manera:Usando Spring's KeyHolder con claves primarias generadas por programación

KeyHolder key = new GeneratedKeyHolder(); 
jdbcTemplate.update(Constants.INSERT_ORDER_STATEMENT, params, key); 

Sin embargo, cuando corro esta declaración, me estoy haciendo:

org.springframework.dao.DataRetrievalFailureException: The generated key is not of a supported numeric type. Unable to cast [oracle.sql.ROWID] to [java.lang.Number] 
    at org.springframework.jdbc.support.GeneratedKeyHolder.getKey(GeneratedKeyHolder.java:73) 

Alguna idea de lo que me falta?

Respuesta

-3

Creo que está utilizando el método incorrecto en JdbcTemplate. El único de los métodos update que parecerían coincidir con su fragmento de código es

int update(String sql, Object... args) 

Si es así, estás pasando params y key como una serie de dos elementos vargs y JdbcTemplate es el tratamiento de key como un aprieto normales parámetros, y mal interpretarlo.

El único método público update en JdbcTemplate que toma un KeyHolder es

int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder) 

por lo que tendrá que reformular el código para utilizar eso.

+2

engañoso, compruebe a continuación la respuesta de Konstantin –

2

Tiene que ejecutar JdbcTemplate.update(PreparedStatementCreator p, KeyHolder k).

La clave devuelta desde la base de datos se inyectará en el objeto de parámetro KeyHolder.

Un ejemplo:

final String INSERT_ORDER_STATEMENT 
     = "insert into order (product_id, quantity) values(?, ?)"; 

KeyHolder keyHolder = new GeneratedKeyHolder(); 
    jdbcTemplate.update(new PreparedStatementCreator() { 
     public PreparedStatement createPreparedStatement(
      Connection connection) throws SQLException { 
       PreparedStatement ps = connection.prepareStatement(
        INSERT_ORDER_STATEMENT, new String[] { "id" }); 
       ps.setInt(1, order.getProductId()); 
       ps.setInt(2, order.getQuantity()); 
       return ps; 
      } 
     }, keyHolder); 

Más información se puede encontrar here en la documentación de referencia.

+0

¡Esto realmente devuelve ROWID en el soporte y no un Número! – supernova

15

acabamos de resolver un problema similar - con Oracle es necesario utilizar otro método (de NamedParameterJdbcOperations) -

int update(String sql, 
      SqlParameterSource paramSource, 
      KeyHolder generatedKeyHolder, 
      String[] keyColumnNames) 
      throws DataAccessException 

con keyColumnNames que contienen columnas generadas automáticamente, en mi caso solo [ "id"]. De lo contrario, todo lo que obtienes es ROWID. Vea Spring doc para más detalles.

+1

Gracias a esto, responda la pregunta mejor que las respuestas anteriores y también resuelva mi problema –

+0

¿No tiene Oracle $ uck? Pero esta es la respuesta correcta –

0

Sin detalles sobre @konstantin respuesta: Aquí hay un ejemplo que funciona completamente: Suponiendo que la base de datos es Oracle y el nombre de columna que el ID generado es "GENERATED_ID" (puede ser cualquier nombre). NOTA: utilicé NamedParameterJdbcTemplate.update (....) En este ejemplo NO JdbcTemplate clase de Spring.

 public Integer insertRecordReturnGeneratedId(final MyObject obj) 
      { 
      final String INSERT_QUERY = "INSERT INTO MY_TABLE VALUES(GENERATED_ID_SEQ.NEXTVAL, :param1, :param2)"; 
      try 
       { 
        MapSqlParameterSource parameters = new MapSqlParameterSource().addValue("param1", obj.getField1()).addValue("param2", obj.getField1()) ; 
        final KeyHolder holder = new GeneratedKeyHolder(); 
        this.namedParameterJdbcTemplate.update(INSERT_QUERY, parameters, holder, new String[] {"GENERATED_ID" }); 
        Number generatedId = holder.getKey(); 
        // Note: USING holder.getKey("GENERATED_ID") IS ok TOO. 
        return generatedId.intValue(); 
       } 
       catch(DataAccessException dataAccessException) 
       { 
     } 
     } 
Cuestiones relacionadas