我正在使用 JDBC 和 HSQLDB 2.2.9。将新行插入数据库并随后保留其id(PK 设置为自动增量)值的最有效和最准确的方法是什么?我需要这样做的原因可能很明显,但我将举例说明以供讨论:
假设有一个Customer表有PersonId一个 FK 约束的字段引用Person表中的一行。我想创建一个新的Customer,但要做到这一点,我需要先创建一个新的Person并使用新的Person.id值来设置Customer.PersonId。
我已经看到了四种方法来解决这个问题:
插入将字段
Person设置为 的行。HSQLDB自动生成下一个值。然后对表执行查询以获取刚刚创建的值并使用它来创建新行。idnullidPersonidCustomer仅检索单个整数值似乎很昂贵。
获取表中的下一个
id值并在语句中Person使用它来手动设置值。使用相同的值进行设置。不需要从 DB 进行后续读取。INSERTPerson.ididCustomer.PersonIdid如果获得了一个值,可能会出现不一致,但是在执行INSERT我的INSERT INTO Person...语句之前,另一个连接在表中执行了一个。执行
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的 forgenKeys。我是否getGeneratedKeys错误地使用了该方法?如果我能让这个工作,这可能是要走的路。再次,执行
INSERT允许自动生成的语句id。然后立即执行CALL IDENTITY()以检索id连接生成的最后一个值(如here所述和this SO question中所述)。这似乎也是一个合理的选择,即使我必须执行额外的
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已经存在的记录)。
这似乎是一个基本问题(也是必不可少的),但我找不到关于最佳方法的太多指导。谢谢。
编辑:我刚刚发现这个问题讨论了我的选项 3。根据接受的答案,我似乎遗漏了
Statement.RETURN_GENERATED_KEYS启用该功能所需的参数。我没有prepareStatement在我的代码片段中显示该方法,但我使用的是单参数版本。我需要使用重载的双参数版本重试。
还有一些其他的 SO 问题与我的问题密切相关。所以,我想我的可能被认为是重复的(不知道我之前是如何错过其他问题的)。但我仍然想要任何关于一种解决方案是否被认为比其他解决方案更好的指导。现在,如果我让选项 3 起作用,我可能会接受。