我正在使用JDBC和HSQLDB 2.2.9。什麼是最有效和準確的方式來插入一個新的行到數據庫中,並且隨後保留其id
(PK設置爲自動增量)值?我需要做的原因可能是很明顯的,但我會討論一個例子說明:如何使用JDBC和HSQLDB檢索先前自動生成的PK ID值
說有,有一個PersonId
場與FK約束從Person
表指的是一排Customer
表。我想創建一個新的Customer
,但要這樣做,我需要先創建一個新的Person
並使用新的Person.id
值來設置Customer.PersonId
。
我見過四種方式來處理這個:
插入
Person
行id
字段設置爲null
。 HSQLDB自動生成下一個id
值。然後在Person
表上執行查詢以獲得剛剛創建的id
值,並使用它創建新的Customer
行。這似乎很昂貴,只是檢索一個整數值。
獲取在
Person
表中的下id
值,並用它在INSERT
語句來手動設置Person.id
值。使用相同的id
值來設置Customer.PersonId
。不需要從數據庫中進行後續讀取。如果獲得
id
值,但在我的INSERT INTO Person...
語句執行之前另一個連接在表中執行INSERT
,則可能會出現不一致。執行
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...
此代碼是用於返回一個
genKeys
空ResultSet
。我是否錯誤地使用getGeneratedKeys
方法?如果我能夠實現這一目標,這可能是一條可行的路。再次執行
INSERT
語句,允許自動生成id
。然後立即執行CALL IDENTITY()
以檢索連接生成的最後一個id
值(如解釋here並在this 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
方法,但我使用的是單參數版本。我需要使用重載的雙參數版本重試。
還有一些其他的問題與我的問題密切相關。所以,我猜我可能被認爲是重複的(不知道我以前錯過了其他問題)。但是我仍然喜歡關於一種解決方案是否比其他解決方案更好的指導。現在,如果我得到選項3的工作,我可能會去。
說實話,我不明白爲什麼你不會致使堅持自己的解決方案1號。在新插入的行的ID上進行SELECT操作通常會產生一個查詢開銷,但同樣,所有其他選項也會這樣做。 –
我不會在'id'上選擇'',而是在包含另一個唯一密鑰的其他字段上。 'id'值就是我要找的。但是,無論查詢的詳細信息如何,您對「查詢常見開銷」的評論仍然存在。但是,我不確定選項3中的開銷。我認爲這些信息將從前面的語句執行中遺留下來。對於選項4,我不確定執行「CALL IDENTITY()」查詢是否比「常規」SELECT語句更便宜。 – neizan
我不知道它是否也是。就個人而言,我不會擔心插入後只有一個查詢,但自然我不知道你的任務的具體細節。 –