【问题标题】:Spring: How to use KeyHolder with PostgreSQLSpring:如何在 PostgreSQL 中使用 KeyHolder
【发布时间】:2013-07-20 05:27:48
【问题描述】:

最近迁移到 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=[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).....

MySQL 的情况下,相同的代码可以正常运行,但在与 POSTGRES 一起使用时会出现密钥失败。数据类型 serial 是否以某种方式导致代码失败,或者我是否正确使用了主键功能?

请指教。

【问题讨论】:

    标签: java spring postgresql spring-jdbc


    【解决方案1】:

    如果框架没有被告知哪一列是键,它将返回表的所有列作为键。

    可以通过给update方法传入一个新的参数来通知它,如下:

    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 和图像)的对象,并且您正在尝试使用 intValue() 函数将对象转换为 int,除非您指向从返回的对象中的“id”键,否则我猜这不起作用“获取密钥()” 干杯, 弗朗切斯科

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-28
        • 1970-01-01
        • 1970-01-01
        • 2021-08-18
        • 2018-08-07
        • 2014-04-08
        • 2020-01-16
        • 1970-01-01
        相关资源
        最近更新 更多