私はJDBCとHSQLDB 2.2.9を使っています。 DBに新しい行を挿入し、その後、id
(PKは自動インクリメントに設定)の値を保持する最も効率的で正確な方法は何ですか?私はこれを行う必要がある理由は、おそらくかなり明白ですが、私は議論のための例を示します:JDBCとHSQLDBを使用して以前に自動生成されたPK ID値を取得する方法
FK制約がPerson
テーブルから行を参照してPersonId
フィールドを持つCustomer
テーブルがあると言います。新しいCustomer
を作成しますが、これを行うには、最初に新しいPerson
を作成し、新しいPerson.id
値を使用してCustomer.PersonId
を設定する必要があります。
私はこれをアプローチする4つの方法を見てきました:
を
null
にid
フィールドを設定Person
行を挿入します。 HSQLDBは自動的に次のid
値を生成します。次にPerson
テーブルのクエリを実行してid
の値を作成し、それを使用して新しいCustomer
行を作成します。これは、単一の整数値を取得するだけでは高額に見えます。
は
Person
表の次のid
値を取得し、手動でPerson.id
値を設定するINSERT
文の中でそれを使用します。同じid
値を使用してCustomer.PersonId
を設定します。その後のDBからの読み取りは必要ありません。id
の値が取得されても、別の接続がINSERT INTO Person...
文が実行される前にテーブルにINSERT
を実行すると、不一致が発生することがあります。上記のオプション1のように
INSERT
ステートメントを実行し、自動生成を許可するように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の質問に記載されています)。私は追加の
executeQuery
を実行する必要がありますが、これは合理的な選択肢のようです。要約すると、最初の2つのオプションは、私は夢中ではないよ、だから、// 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つは大丈夫だと思われますが、私は選択肢4を働かせるだけです。どちらのオプションが優先され、なぜですか?オプション3が最高の場合、何が間違っているのですか?また、私が言及していないより良い方法がありますか?私は 'better'のような言葉が主観的であることは知っていますが、私は単純なDBを使って作業しており、可能性のある不一致にDBを開放しない最も直接的な解決策を求めています。すでに存在するid
のレコードを作成します)。
これは基本的な質問(および必須)のようですが、私はそれを行う最良の方法について多くの指針を見つけることができませんでした。ありがとう。
編集:私はちょうど受け入れ答えによると、私のオプション3を説明し this質問を見つけ 、私がその機能を有効にするために必要な
Statement.RETURN_GENERATED_KEYS
パラメータを除外して表示されます。自分のコードスニペットに
prepareStatement
メソッドを表示しませんでしたが、私は単一のパラメータバージョンを使用していました。オーバーロードされた2パラメータバージョンを使用して再試行する必要があります。
私の質問に密接に関連しているこの質問には、他にもいくつかの質問があります。だから、私は私が重複していると思うかもしれないと思う。しかし、私はまだ、あるソリューションが他のソリューションよりも優れているかどうかについてのガイダンスを欲しがっています。今のところ、オプション3を稼働させると、おそらくこれで動くでしょう。
正直に言うと、私はあなたのソリューションNo1のに固執won't理由を知るドント。新しく挿入された行のIDでSELECTを実行すると、通常はクエリのオーバーヘッドが発生しますが、他のオプションもすべて同じです。 –
私は 'id'で' SELECT'するのではなく、別の一意のキーを構成する他のフィールドの束にします。 'id'の値は私が探している値になります。しかし、 "クエリの通常のオーバーヘッド"に関するあなたのコメントは、クエリの詳細にかかわらず、まだ立っています。しかし、オプション3に伴うオーバーヘッドについてはわかりませんでした。前のステートメント実行から情報が残っていると思いました。オプション4では、 'CALL IDENTITY()'のクエリを "通常の" SELECT文よりも安価に実行できたかどうかはわかりませんでした。 – neizan
もしそうなら、私は知らない。個人的には、挿入後に1つのクエリーについて心配するつもりはありませんが、当然あなたの仕事の詳細はわかりません。 –