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

标签 java jdbc hsqldb

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

假设有一个 Customer具有 PersonId 的表带有 FK 约束的字段引用来自 Person 的行 table 。我要新建一个Customer ,但要做到这一点,我需要先创建一个新的 Person并使用新的 Person.id要设置的值 Customer.PersonId .

我见过四种方法来解决这个问题:

  • 插入 Person行设置 id字段到 null . HSQLDB 生成下一个 id值自动。然后对Person进行查询表获取 id刚刚创建的值并使用它来创建新的 Customer排。

    仅检索单个整数值似乎很昂贵。
  • 获取下一个 id Person 中的值表并在 INSERT 中使用它设置 Person.id 的语句手动值。使用相同的 id要设置的值 Customer.PersonId .不需要从 DB 进行后续读取。

    如果 id 可能会出现不一致的情况获得值,但另一个连接执行 INSERT在我面前的 table INSERT INTO Person...语句被执行。
  • 执行 INSERT语句,如上面的选项 1,设置 id=null允许自动生成。然后使用 getGeneratedKeys检索在最后一条语句中生成的 key 的方法。

    我认为这听起来是一个不错的选择,但我无法让它发挥作用。这是我的代码片段:
    // PreparedStatement prepared previously...
    preparedStatement.executeUpdate();
    ResultSet genKeys = preparedStatement.getGeneratedKeys();
    int id;
    if (genKeys.next()) {
        id = genKeys.getInt(1);
    }
    // Finish up method...
    

    此代码返回一个空 ResultSetgenKeys .我在使用 getGeneratedKeys方法不对?如果我能让这个工作,这可能是要走的路。
  • 再次执行 INSERT允许自动生成的语句 id .然后立即执行CALL IDENTITY()检索最后一个 id由连接生成的值(如 herethis SO 问题中所述)。

    这似乎也是一个合理的选择,即使我必须执行额外的 executeQuery .从积极的方面来说,我实际上能够让它与以下代码一起工作:
    // 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...
    

  • 所以,总而言之,前两个选项我并不疯狂。后两个似乎没问题,但我只能让选项 4 起作用。哪个选项是首选,为什么?如果选项 3 是最好的,我做错了什么?另外,有没有我没有提到的更好的方法?我知道像“更好”这样的词可能是主观的,但我正在使用一个简单的数据库,并且想要最直接的解决方案,该解决方案不会打开数据库以应对可能的不一致并且不会增加事务失败率(由于尝试使用已存在的 id 创建记录)。

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

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

    还有一些其他 SO 问题与我的问题密切相关。所以,我想我的可能被认为是重复的(不确定我之前是如何错过其他问题的)。但我仍然希望获得有关是否认为一种解决方案比其他解决方案更好的任何指导。现在,如果我让选项 3 起作用,我可能会选择它。

    最佳答案

    我没有足够的声誉来评论 neizan 的回答,但这是我解决同样问题的方法:

  • 该列看起来像一个 ID 列,但它没有定义为 IDENTITY;
  • 如上所述,您需要指定 RETURN_GENERATED_KEYS。
  • 看起来如果您按顺序执行 2 INSERT,则第二个不会返回生成的 key 。请改用“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);
        }
    }
    

    关于java - 如何使用 JDBC 和 HSQLDB 检索以前自动生成的 PK ID 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17858499/

    相关文章:

    sqlite - 嵌入式(进程内)数据库 H2、Hsqldb、Apache Derby、SQLite (JDBC) 中的并发

    java - 为什么蓝色条在菜单中重叠?

    java - 为什么 HashSet 区分 0.0 和 -0.0

    java - 仅适用于 JSP、Servlet 和 Bean 的简单架构

    mysql - 连接到 MySql 的 Scala Play 显示运行时错误 "Table ' token '不存在”

    java - 如何确定java中的数据库约束冲突?

    在生产中 hibernate 超音速?

    java - 设计时泛型的问题

    java - 从 ConnectionPools 获取和释放 JDBC 连接的频率?

    java - 如何创建 Activity 对象 'IN'条件查询