Использование ключа Spring с программно генерируемыми первичными ключами
-
26-09-2019 - |
Вопрос
Я использую Spring NamedParameterJDBCTEMPTEMPTEMPTEMPTEM для выполнения вставки в таблицу. Таблица использует NextVal на последовательности для получения первичного ключа. Затем я хочу, чтобы этот сгенерированный идентификатор был передан мне. Я использую реализацию Spring Keyholder, как это:
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)
Любые идеи, что мне не хватает?
Решение
Я думаю, что вы используете неправильный метод на JdbcTemplate
. Отказ Единственный из update
методы, которые, казалось бы, чтобы соответствовать вашим фрагменте кода
int update(String sql, Object... args)
Если так, вы проходите params
а также key
как двухэлементный массив Vargs и JdbcTemplate
лечится key
как нормальный параметры связывания и неправильно интерпретировать.
Единственная публика update
метод включения 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. Видеть Весной док для деталей.
Вы должны выполнить JdbcTemplate.update(PreparedStatementCreator p, KeyHolder k)
.
Ключ, возвращенный из базы данных, будет введен в KeyHolder
объект параметра.
Пример:
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 и столбца, который сгенерированный для хранения ID «Genered_id» (может быть любое имя). Примечание: я использовал namedparameterjdbctemplate.update (....) В этом примере не класс JDBCTEMPLETS класса пружины.
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 )
{
}
}
С MySQL
CREATE TABLE `vets` (
`id` int(4) unsigned NOT NULL AUTO_INCREMENT,
`first_name` varchar(30) DEFAULT NULL,
`last_name` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `last_name` (`last_name`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
public @Data class Vet {
private int id;
private String firstname;
private String lastname;
}
@Repository
public class VetDaoImpl implements VetDao {
/** Logger. */
private static final Logger LOGGER = LoggerFactory.getLogger(VetDaoImpl.class);
private static final String INSERT_VET = "INSERT INTO vets (first_name, last_name) VALUES (:first_name, :last_name)";
@Autowired
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Override
public Number insertVet(final Vet vet) {
MapSqlParameterSource paramSource = new MapSqlParameterSource();
paramSource.addValue("first_name", vet.getFirstname());
paramSource.addValue("last_name", vet.getLastname());
KeyHolder keyHolder = new GeneratedKeyHolder();
int nbRecord = namedParameterJdbcTemplate.update(INSERT_VET, paramSource, keyHolder, new String[] {"id" });
LOGGER.info("insertVet: id ["+keyHolder.getKey()+"]");
return nbRecord;
}
}