Spring: How to use KeyHolder with PostgreSQL

≡放荡痞女 提交于 2020-07-18 03:31:50

问题


Recently migrated to POSTGRESQL, I am trying to obtain the uniquely generated key on creating a new entry into the db table. The table screenstable looks like this:

CREATE TABLE screenstable
(
  id serial NOT NULL,
  screenshot bytea,
  CONSTRAINT screen_id PRIMARY KEY (id )
)

The method that inserts data into screenstable is as follows:

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

and ImageBean is

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;
    }
}

But running the code give the following exception

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=[B@db59df}]
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=[B@db59df}]
        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).....

The same code used to run fine in case of MySQL but is failing with keys when used with POSTGRES. Is the datatype serial somehow responsible for the code failing or may be I am using the primary key feature correctly?

Please advice.


回答1:


If the framework is not informed about which column is the key, it will return all columns of the table as keys.

You can inform it by passing a new parameter to the update method, as follows:

template.update(query, data, keyHolder, new String[] { "id" });

See NamedParameterJdbcTemplate.update(sql, paramSource, generatedKeyHolder, keyColumnNames)




回答2:


You can also stay with JdbcTemplate but in this situation you have to check it:

    jdbcTemplate.update(this, holder);
    Long newId;
    if (holder.getKeys().size() > 1) {
        newId = (Long)holder.getKeys().get("your_id_column");
    } else {
        newId= holder.getKey().longValue();
    }

The GeneratedKeyHolder class throws exception due to the fact that class only knows what should be returned when has one key (and that key needs to be Number instance because getKey method returns Number object).

On situation when jdbc driver return multiple keys you have to determine the generated key column (either before update or after). Please take a look at source code of the GeneratedKeyHolder#getKey - it is very simple to analyze. There is checking of key list size and with more than key Spring does not know which key should be returned and that's why the exception is returned.

Note: Please remember that approach won't work with Oracle because Oracle returns something like ROWID. With Oracle you have to use NamedParameterJdbcTemplate.




回答3:


Just a guess from a quick look... keyHolder.getKey().intValue() should be keyHolder.getKey()["id"].intValue() (or something similar)? getKey() function returns an object with multiple keys (id and image) and you are trying to turn the object to int with intValue() function which I guess does not work unless you point to the "id" key in the object returned from "getKey()" Cheers, Francesco



来源:https://stackoverflow.com/questions/17771306/spring-how-to-use-keyholder-with-postgresql

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!