Spring: Как использовать KeyHolder с PostgreSQL
Недавно перенесенный в POSTGRESQL, я пытаюсь получить уникально сгенерированный ключ при создании новой записи в таблицу db. Таблица screenstable
выглядит так:
CREATE TABLE screenstable
(
id serial NOT NULL,
screenshot bytea,
CONSTRAINT screen_id PRIMARY KEY (id )
)
Метод, который вставляет данные в screenstable
, выглядит следующим образом:
@Autowired NamedParameterJDBCTemplate template;
public int insertImage(ImageBean imageBean){
String query = "insert into screenstable (screenshot) values (:image)";
SqlParameterSource data = new BeanPropertySqlParameterSource(imageBean);
KeyHolder keyHolder = new GeneratedKeyHolder();
template.update(query, data, keyHolder);
return keyHolder.getKey().intValue();
}
и ImageBean
-
import java.util.Arrays;
public class ImageBean {
private int id;
private byte[] image;
@Override
public String toString() {
return "ImageBean [id=" + id + ", image=" + Arrays.toString(image)
+ "]";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public byte[] getImage() {
return image;
}
public void setImage(byte[] image) {
this.image = image;
}
}
Но запуск кода дает следующее исключение
15:33:20,953 ERROR JsonParseExceptionMapper:15 - org.springframework.dao.InvalidDataAccessApiUsageException: The getKey method should only be used when a single key is returned. The current key entry contains multiple keys: [{id=3, screenshot=[[email protected]}]
org.springframework.dao.InvalidDataAccessApiUsageException: The getKey method should only be used when a single key is returned. The current key entry contains multiple keys: [{id=3, screenshot=[[email protected]}]
at org.springframework.jdbc.support.GeneratedKeyHolder.getKey(GeneratedKeyHolder.java:65)
at some.project.model.FeedbackDao.insertImage(FeedbackDao.java:20)
at some.project.rest.FeedsRest.pluginCheck(FeedsRest.java:62)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597).....
Тот же код, который использовался для прекращения работы в случае MySQL
, но не работает с ключами при использовании с POSTGRES. Является ли тип данных serial
как-то ответственным за отказ кода или может быть я правильно использую функцию первичного ключа?
Пожалуйста, совет.
Ответы
Ответ 1
Если фреймворк не информирован о том, какой столбец является ключом, он вернет все столбцы таблицы в качестве ключей.
Вы можете сообщить об этом, передав новый параметр методу обновления следующим образом:
template.update(query, data, keyHolder, new String[] { "id" });
См. NamedParameterJdbcTemplate.update(sql, paramSource, generatedKeyHolder, keyColumnNames)
Ответ 2
Вы также можете остаться с JdbcTemplate, но в этой ситуации вы должны его проверить:
jdbcTemplate.update(this, holder);
Long newId;
if (holder.getKeys().size() > 1) {
newId = (Long)holder.getKeys().get("your_id_column");
} else {
newId= holder.getKey().longValue();
}
Класс GeneratedKeyHolder вызывает исключение из-за того, что класс знает, что должно быть возвращено, когда имеет один ключ (и этот ключ должен быть экземпляром Number, потому что метод getKey возвращает объект Number).
В ситуации, когда драйвер jdbc возвращает несколько ключей, вы должны определить сгенерированный ключевой столбец (до обновления или после). Пожалуйста, посмотрите исходный код GeneratedKeyHolder # getKey - его очень просто проанализировать. Существует проверка размера списка ключей и более чем ключ Spring не знает, какой ключ должен быть возвращен и почему возвращается исключение.
Примечание.. Помните, что этот подход не будет работать с Oracle, потому что Oracle возвращает что-то вроде ROWID. С Oracle вы должны использовать NamedParameterJdbcTemplate.
Ответ 3
Просто догадаться от быстрого взгляда... keyHolder.getKey(). intValue() должен быть keyHolder.getKey() [ "id" ]. intValue() (или что-то подобное)?
Функция getKey() возвращает объект с несколькими ключами (id и изображение), и вы пытаетесь превратить объект в int с помощью функции intValue(), которая, как я полагаю, не работает, если вы не указали на ключ "id" в объекте, возвращаемом из "GetKey()"
Ура,
Francesco