【问题标题】:spring jdbc and composite primary keysspring jdbc和复合主键
【发布时间】:2010-06-28 15:22:54
【问题描述】:

spring jdbc 中有没有办法在插入行时返回复合主键。 这个复合主键由不同序列的值组成

非常感谢任何帮助

问候 达米安

【问题讨论】:

  • 我想澄清一下“Spring JDBC”;您是指 Hibernate 映射还是其他一些 JPA 框架?我不知道 Spring 提供的任何内置 JDBC 功能。另一个注意事项:当表的记录由复合键唯一标识时,使用 ONE 生成的主键列通常是一个好主意。特别是如果该复合键只是多个生成的列。我会审查您的数据库设计,看看简化事情是否会使使用这些框架更容易。

标签: java spring jdbc


【解决方案1】:

这是一个完整的例子(在 PostgreSQL 8.4 上测试):

我的桌子:

CREATE TABLE test
(
  id serial NOT NULL,
  otherid serial NOT NULL,
  val text,
  CONSTRAINT test_pkey PRIMARY KEY (id, otherid)
)

这是您取回密钥的方式:

public void doStuff() {
    KeyHolder keyHolder = new GeneratedKeyHolder();
    jdbcTemplate.update(
            new PreparedStatementCreator() {
                public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
                    PreparedStatement ps = connection.prepareStatement("insert into test(val) values (?)", Statement.RETURN_GENERATED_KEYS);
                    ps.setInt(1, 42);
                    return ps;
                }
            },
            keyHolder);

    keyHolder.getKeys().get("id");
    keyHolder.getKeys().get("otherid");
}

现在,如果您想直接从 keyHolder 获取复合键作为某个类的实例,这并不简单。

JdbcTemplate 使用 ColumnMapRowMapper 映射生成的键(生成的键作为结果集返回,至少在 PostgreSQL 上。它实际上返回整行,就好像您在刚刚插入的行上执行选择一样)。相同的 ColumnMapRowMapper 用于 JdbcTemplate 中的许多其他地方。

这里唯一可能的扩展点是 KeyHolder 本身。以下是您可以执行的操作:

public void doStuff() {
    CompositeKeyHolder keyHolder = new CompositeKeyHolder();
    ... same code here ...

    keyHolder.getCompositeKey();
}


class CompositeKeyHolder extends GeneratedKeyHolder {
    private boolean converted;

    public CompositeKey getCompositeKey() {
        return new CompositeKey((Integer)this.getKeys().get("id"), (Integer)this.getKeys().get("otherid"));
    }
}


class CompositeKey {

    private Integer id;

    private Integer otherId;

    CompositeKey(Integer id, Integer otherId) {
        this.id = id;
        this.otherId = otherId;
    }

    public Integer getId() {
        return id;
    }

    public Integer getOtherId() {
        return otherId;
    }

}

【讨论】:

    【解决方案2】:

    这是单键的基本概念。最后的长id是关键。如果您有多个序列,我建议您只使用两个单独的语句来获取每个生成的密钥。

    JdbcTemplate template = getJdbcTemplate();
    KeyHolder keyHolder = new GeneratedKeyHolder();
    template.update(
        new PreparedStatementCreator() {
            public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
                PreparedStatement ps = connection.prepareStatement(...);
                return ps;
            }
        },
        keyHolder);
    long id = keyHolder.getKey().longValue();
    

    【讨论】:

    • 单键很简单,不需要解释。复合键是问题所在,似乎没有简单/有效的解决方案。
    • 确实如此,但我不确定 Damien 是否知道简单的答案。另一部分是,如果您在一个语句中使用 2 个生成的键将数据插入到表中,这听起来像是一个潜在的设计缺陷。
    【解决方案3】:

    您使用的是什么数据库服务器? MySQL 只允许每个表有一个 auto_increment 字段,我想这通常是这种情况,但是在不知道您的设置的情况下很难说。假设您的表中只有一个 auto_generated 字段,您的 INSERT 必须知道进入第二个 PK 字段的值。 Robert 的代码应该可以用于检索生成的键值,最简洁的解决方案可能是在使用此生成的键和您已经持有的值之后执行 SELECT。

    【讨论】:

    • MySQL 不是其他数据库的好指南——它很粗糙和原始。适当的数据库很好地支持复合键,但 Spring JDBC 似乎对这个概念没有很好的支持。
    【解决方案4】:

    我认为你需要的是GeneratedKeyHolder.getKeys()。代码看起来像this example,除了你必须调用

    keyHolder.getKeys()
    

    而不是

    keyHolder.getKey()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多