如何使用JDBC和HSQLDB检索以前自动生成的PK ID值

时间:2013-07-25 12:49:06

标签: java jdbc hsqldb

我正在使用JDBC和HSQLDB 2.2.9。将新行插入数据库并随后保留其id(PK设置为自动增量)值的最有效和准确的方法是什么?我需要这样做的原因可能非常明显,但我将用一个例子来说明:

假设有一个Customer表,其中PersonId字段的FK约束引用了Person表中的一行。我想创建一个新的Customer,但要执行此操作,我需要先创建一个新的Person并使用新的Person.id值来设置Customer.PersonId

我已经看到了四种方法:

  1. 插入Person行,将id字段设置为null。 HSQLDB自动生成下一个id值。然后在Person表上执行查询以获取刚刚创建的id值,并使用它来创建新的Customer行。

    仅检索单个整数值似乎很昂贵。

  2. 获取id表中的下一个Person值,并在INSERT语句中使用它来手动设置Person.id值。使用相同的id值设置Customer.PersonId。不需要随后从DB读取。

    如果获得id值,但在执行INSERT语句之前另一个连接在表中执行INSERT INTO Person...,则可能会出现不一致。

  3. 执行INSERT语句,如上面的选项1所示,设置id=null以允许自动生成。然后使用getGeneratedKeys方法检索在最后一个语句中生成的密钥。

    我认为这听起来是个不错的选择,但我无法让它发挥作用。这是我的代码片段:

    // PreparedStatement prepared previously...
    preparedStatement.executeUpdate();
    ResultSet genKeys = preparedStatement.getGeneratedKeys();
    int id;
    if (genKeys.next()) {
        id = genKeys.getInt(1);
    }
    // Finish up method...
    

    此代码为ResultSet返回空genKeys。我错误地使用getGeneratedKeys方法吗?如果我可以让这个工作,这可能是要走的路。

  4. 再次执行允许自动生成INSERT的{​​{1}}语句。然后立即执行id以检索连接生成的最后CALL IDENTITY()值(如here所解释并在this SO问题中提及)。

    这似乎也是一个合理的选择,即使我必须执行额外的id。从积极的方面来说,我实际上能够使用以下代码:

    executeQuery
  5. 总而言之,前两个选项我并不疯狂。第二个似乎没问题,但我只能选择4来工作。哪个选项更受欢迎?为什么?如果选项3是最好的,我做错了什么?还有,有没有更好的方法,我没有提到?我知道像'更好'这样的词可以是主观的,但我正在使用一个简单的数据库,并希望最直接的解决方案不会打开数据库可能的不一致,并且不会增加事务失败率(由于尝试使用已存在的// INSERT statement executed here... statement = connection.createStatement(); ResultSet rs = statement.executeQuery("CALL IDENTITY();"); int id; if (rs.next()) id = rs.getInt(1); // Finish up method... 创建记录。

    这似乎是一个基本问题(也是必不可少的),但我找不到最佳方法的指导。感谢。

    <小时/> 编辑: 我刚发现this问题讨论了我的选项3.根据接受的答案,我似乎遗漏了启用该功能所需的id参数。我没有在我的代码段中显示Statement.RETURN_GENERATED_KEYS方法,但我使用的是单参数版本。我需要重试使用重载的双参数版本。

    还有一些其他SO问题出现在与我的问题密切相关的问题上。所以,我想我的可能被视为重复(不知道我之前是否错过了其他问题)。但我仍然喜欢任何一个解决方案被认为比其他解决方案更好的指导。现在,如果我选择3工作,我可能会继续这样做。

2 个答案:

答案 0 :(得分:8)

我没有足够的声誉评论neizan的答案,但这是我如何解决同样的问题:

  • 该列看起来像ID列,但未定义为IDENTITY;
  • 如上所述,您需要指定RETURN_GENERATED_KEYS。
  • 看起来如果按顺序执行2 INSERT,第二个不会返回生成的键。改为使用“CALL IDENTITY()”。

使用HSQLDB 2.2.9的示例:

CREATE TABLE MY_TABLE (
 ID INTEGER IDENTITY,
 NAME VARCHAR(30)
)

然后在Java中:

PreparedStatement result = cnx.prepareStatement(
    "INSERT INTO MY_TABLE(ID, NAME) VALUES(NULL, 'TOM');",
    RETURN_GENERATED_KEYS);
int updated = result.executeUpdate();
if (updated == 1) {
    ResultSet generatedKeys = result.getGeneratedKeys();
    if (generatedKeys.next()) {
        int key = generatedKeys.getInt(1);
    }
}

答案 1 :(得分:1)

这里行动不多,所以我会继续回答这个问题。在玩了不同的选项之后,在看到this问题之后,我能够让我的选项3工作。就像我在编辑问题中提到的那样,我将使用选项3.选项4也工作正常,但由于链接问题的接受答案是由信誉良好的来源提供的,所以我坚持这一点。我希望在开始这个问题之前我已经看过那个问题/答案,我已经节省了一些时间!