Использование держателя ключей Spring с программно сгенерированными первичными ключами
Я использую Spring NamedParameterJdbcTemplate для выполнения вставки в таблицу. Таблица использует NEXTVAL в последовательности для получения первичного ключа. Затем я хочу, чтобы этот сгенерированный идентификатор был передан мне. Я использую реализацию KeyHolder Spring следующим образом:
KeyHolder key = new GeneratedKeyHolder();
jdbcTemplate.update(Constants.INSERT_ORDER_STATEMENT, params, key);
однако, когда я запускаю этот оператор, я получаю:
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)
есть идеи, что мне не хватает?
4 ответов
Я думаю, что вы используете неправильный метод на JdbcTemplate
. Единственный из update
методы, которые, казалось бы, соответствуют вашему фрагменту кода
int update(String sql, Object... args)
если это так, вы передаете params
и key
как два элемента массива варгс, а JdbcTemplate
лечение key
как обычные параметры привязки и неверная интерпретация.
единственная общественная update
метод on JdbcTemplate
что происходит KeyHolder
и
int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder)
таким образом, вам нужно будет перефразировать свой код использовать это.
просто решил аналогичную проблему - с Oracle вам нужно использовать другой метод (от NamedParameterJdbcOperations
) -
int update(String sql,
SqlParameterSource paramSource,
KeyHolder generatedKeyHolder,
String[] keyColumnNames)
throws DataAccessException
С keyColumnNames, содержащими автоматически сгенерированные столбцы, в моем случае просто ["Id"]. В противном случае все, что вы получаете, это ROWID. См.Spring doc для сведения.
вы должны выполнить JdbcTemplate.update(PreparedStatementCreator p, KeyHolder k)
.
ключ, возвращенный из базы данных, будет введен в KeyHolder
объект parameter.
пример:
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);
более подробную информацию можно найти здесь в справочной документации.
нет подробного ответа на @konstantin: вот полностью рабочий пример: Предполагая, что база данных-Oracle, а имя столбца, в котором хранится сгенерированный идентификатор, - "GENERATED_ID" (может быть любым именем). Примечание: я использовал NamedParameterJdbcTemplate.обновление.(...) В этом примере не jdbctemplate класса 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 )
{
}
}