我正在使用JDBC和HSQLDB 2.2.9。将新行插入数据库并随后保留其id
(PK设置为自动增量)值的最有效和准确的方法是什么?我需要这样做的原因可能非常明显,但我将用一个例子来说明:
假设有一个Customer
表,其中PersonId
字段的FK约束引用了Person
表中的一行。我想创建一个新的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
语句之前另一个连接在表中执行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
返回空genKeys
。我错误地使用getGeneratedKeys
方法吗?如果我可以让这个工作,这可能是要走的路。
再次执行允许自动生成INSERT
的{{1}}语句。然后立即执行id
以检索连接生成的最后CALL IDENTITY()
值(如here所解释并在this SO问题中提及)。
这似乎也是一个合理的选择,即使我必须执行额外的id
。从积极的方面来说,我实际上能够使用以下代码:
executeQuery
总而言之,前两个选项我并不疯狂。第二个似乎没问题,但我只能选择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工作,我可能会继续这样做。
答案 0 :(得分:8)
我没有足够的声誉评论neizan的答案,但这是我如何解决同样的问题:
使用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也工作正常,但由于链接问题的接受答案是由信誉良好的来源提供的,所以我坚持这一点。我希望在开始这个问题之前我已经看过那个问题/答案,我已经节省了一些时间!