私は JDBC と HSQLDB 2.2.9 を使用しています。id
新しい行を DB に挿入し、その後、その(自動インクリメントに設定された PK) 値を保持する最も効率的で正確な方法は何ですか? これを行う必要がある理由はおそらくかなり明白ですが、議論のために例を挙げて説明します。
テーブルの行を参照する FK 制約を持つフィールドを持つCustomer
テーブルがあるとします。新しい を作成したいのですが、これを行うには、まず新しい を作成し、新しい値を使用してを設定する必要があります。PersonId
Person
Customer
Person
Person.id
Customer.PersonId
これにアプローチする 4 つの方法を見てきました。
フィールドを に
Person
設定して行を挿入します。HSQLDB は次の値を自動的に生成します。次に、テーブルに対してクエリを実行して、作成したばかりの値を取得し、それを使用して新しい行を作成します。id
null
id
Person
id
Customer
これは、単一の整数値を取得するだけでもコストがかかるようです。
テーブル内の次の
id
値を取得し、それをステートメントで使用して値を手動で設定します。同じ値を使用して設定します。その後の DB からの読み取りは必要ありません。Person
INSERT
Person.id
id
Customer.PersonId
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
自動生成を許可するステートメントを実行しid
ます。次に、すぐに実行CALL IDENTITY()
して、接続によって生成された最後のid
値を取得します(ここで説明され、この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...
つまり、要約すると、最初の 2 つのオプションについては、あまり好きではありません。2 番目の 2 つは問題ないように見えますが、オプション 4 しか機能しませんでした。どのオプションが優先され、その理由は? オプション 3 が最適な場合、何が間違っているのでしょうか? また、私が言及していないより良い方法はありますか?「より良い」などの言葉が主観的である可能性があることは知っていますが、私は単純な DB を使用しており、DB を不整合の可能性に開かず、トランザクションの失敗率を増加させない最も直接的なソリューションが必要です (id
既に存在するでレコードを作成します)。
これは基本的な (そして不可欠な) 質問のように思えますが、最善の方法についてのガイダンスはあまり見つかりませんでした。ありがとう。
編集:オプション3について説明するこの質問を見つけました。受け入れられた回答によると、
Statement.RETURN_GENERATED_KEYS
その機能を有効にするために必要なパラメーターを省略していたようです。コード スニペットではメソッドを示しませんでしたprepareStatement
が、単一パラメーター バージョンを使用していました。オーバーロードされた 2 パラメーター バージョンを使用して再試行する必要があります。
私の質問に密接に関連している他のいくつかのSOの質問もあります。したがって、私の質問は重複していると見なされる可能性があると思います(以前に他の質問を見逃した方法はわかりません)。しかし、ある解決策が他の解決策よりも優れていると見なされるかどうかについてのガイダンスが欲しい. 今のところ、オプション 3 が機能する場合は、おそらくそれを使用します。