2009-06-16 19 views
9

テーブルに行を挿入し、生成されたIDを1つのステートメントで取得する方法はありますか?私はJDBCを使用したい、IDはシーケンスによって生成されるか、または自動インクリメントフィールドになります。同じステートメントに挿入されたIDのIDを取得する

ありがとうございました。

ジョンPollancre

+0

は、あなたはそれが可能だったと仮定すると、あなたが何をしたいのかの例を与えることができます? – skaffman

+0

もちろん。 voidテーブルA(id [autoincrement]、field)を考えてみましょう。 long id = jdbcStatement.execute(「A(フィールド)値( 'blah')」に挿入); または long id = jdbcStatement.execute(「A(id、field)値(sequence.nextval、 'blah')」)に挿入します。 ID = 1、DBに1回だけアクセスするようにしたい –

+0

+1 Javaの側でリンクされているオブジェクトを挿入するときに便利な質問です。 –

答えて

0

自動生成されたIDの値は、他の文を同時に実行することができるので、INSERTが実行された後までは知られており、RDBMSは、第移行どちらスケジュールする方法を決定するために取得されていません。

INSERTステートメントの式で呼び出す関数は、新しい行が挿入される前に評価する必要があるため、生成されるID値はわかりません。

私はあなたが求めているものに近い二つの選択肢を考えることができます:あなたが生成されたIDキー値へのアクセスを持っているので、

  • は、INSERT後に実行トリガを書きます。

  • 手順で他のコードを実行し、最後に生成されたIDを照会できるように、挿入をラップする手順を記述します。

はしかし、私はあなたが本当に求めていることは、あなたが他のセッションでも、行を挿入して、自分のID値を生成している場合でも、あなたの現在のセッションによって最後に生成されたID値を問い合わせることができるかどうかである疑いがあります。 自動インクリメント機能を提供するすべてのRDBMSがこの値を照会する方法を提供し、現在のセッションスコープで生成された最後のIDを通知することが保証されます。これは他のセッションで行われた挿入の影響を受けません。 getGeneratedKeys()を使用して

+0

"...他のステートメントが同時に実行される可能性があるため..." 私はそれについて疑問に思っていました。これを防ぐためにJavaでメソッドを同期するのはどうですか? –

+0

アプリケーション・コードにクリティカル・セクションを設定するか、明示的にテーブル・ロックを要求することによって、トランザクションをシリアライズすることができますが、SQLには同じステートメント内のIDを要求する構文はありません。 –

10

:一貫性のあるビューを取得するように配列することにより生成されたidが

insert into table values (sequence.NextVal, otherval) 
select sequence.CurrVal 

を介して取得することができる

resultSet = pstmt.getGeneratedKeys(); 

if (resultSet != null && resultSet.next()) { 
    lastId = resultSet.getInt(1); 
} 
+0

すごい!そのようなことを聞​​いたのは初めてだ!シーケンスによって生成されたIDで動作すると思いますか? ありがとう、dfa! –

+0

ちょうどそれを試す:-) – dfa

+1

Oracle JDBCドライバは、getGeneratedKeysのROWIDを返します.Oracleには自動生成キーの実際の概念がないため、シーケンスを持ちますが、明示的にフィールドを設定する必要がありますINSERTまたはトリガーのいずれかに入力します。私はVincentが記述したRETURNINGメソッドを使用します。 –

0

は、同じトランザクション内で実行しました。

+0

これは以下のRobert Mによって指摘されているようにスレッドセーフではありません。 – massfords

6

RETURNING句を使用して、更新または挿入した列の値を取得できます。これはトリガーで動作します(i-e:トリガーの実行後に実際に挿入された値を取得します)。考えてみましょう:

SQL> CREATE TABLE a (ID NUMBER PRIMARY KEY); 

Table created 
SQL> CREATE SEQUENCE a_seq; 

Sequence created 
SQL> VARIABLE x NUMBER; 
SQL> BEGIN 
    2  INSERT INTO a VALUES (a_seq.nextval) RETURNING ID INTO :x; 
    3 END; 
    4/

PL/SQL procedure successfully completed 
x 
--------- 
1 

SQL>/

PL/SQL procedure successfully completed 
x 
--------- 
2 
0

は、私はあなたがこの参考と思う:

私は 自動インクリメントidを持つテーブルを持っています。時間から 時までこの テーブルに行を挿入したいが、 を新しく挿入された行のpkと知りたい。 。

String query = "BEGIN INSERT INTO movement (doc_number) VALUES ('abc') RETURNING id INTO ?; END;"; 
OracleCallableStatement cs = (OracleCallableStatement) conn.prepareCall(query); 
cs.registerOutParameter(1, OracleTypes.NUMBER); 
cs.execute(); 
System.out.println(cs.getInt(1)); 

出典:私はコメントできないThread: Oracle/JDBC Error when Returning values from an Insert

0

、そうでない場合、私はちょうどDFAのポストに追加しただろうが、次はストレートJDBCでこの機能の例です。あなたは、このような春のようなものを使用している場合

http://www.ibm.com/developerworks/java/library/j-jdbcnew/

しかし、彼らはあなたのための血みどろの詳細の多くをマスクします。それが助けになることができれば、JDBCの詳細である良いSpring Chapter 11だけです。それを使用すると、私は頭痛の多くを救ってくれました。

1

私はVinko Vrsalovicのポストに追加しているだろうそれ以外はコメントできない:

The id generated by a sequence can be obtained via 

insert into table values (sequence.NextVal, otherval) 
select sequence.CurrVal 

ran in the same transaction as to get a consistent view. 

更新・デ・シーケンスをそれからNEXTVALを取得した後、自律型トランザクションです。そうしないと、別のセッションがシーケンスから同じ値を取得します。したがって、別のセクションが挿入と選択の間のシーケンスから選択されている場合、currvalを取得すると、挿入されたIDは取得されません。

よろしく、 ロブ実際

+0

ネストされたトランザクションはどうですか? (オラクルの専門家ではないので、間違った質問をしてください) –

3

は、私が仕事をCURRVALが続くのnextvalんだと思います。ここでは、2つのスレッド、つまり最初にnextvalを実行し、次にcurrvalを実行し、2つ目のスレッドがnextvalを実行する2つのスレッドでこの動作をシミュレートするコードがあります。

public void checkSequencePerSession() throws Exception { 
    final Object semaphore = new Object(); 
    Runnable thread1 = new Runnable() { 
     public void run() { 
      try { 
       Connection con = getConnection(); 
       Statement s = con.createStatement(); 
       ResultSet r = s.executeQuery("SELECT SEQ_INV_BATCH_DWNLD.nextval AS val FROM DUAL "); 
       r.next(); 
       System.out.println("Session1 nextval is: " + r.getLong("val")); 
       synchronized(semaphore){ 
       semaphore.notify(); 
       } 
       synchronized(semaphore){ 
       semaphore.wait(); 
       } 
       r = s.executeQuery("SELECT SEQ_INV_BATCH_DWNLD.currval AS val FROM DUAL "); 
       r.next(); 
       System.out.println("Session1 currval is: " + r.getLong("val")); 
       con.commit(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }; 
    Runnable thread2 = new Runnable(){ 
     public void run(){ 
      try{ 
       synchronized(semaphore){ 
       semaphore.wait(); 
       } 
       Connection con = getConnection(); 
       Statement s = con.createStatement(); 
       ResultSet r = s.executeQuery("SELECT SEQ_INV_BATCH_DWNLD.nextval AS val FROM DUAL "); 
       r.next(); 
       System.out.println("Session2 nextval is: " + r.getLong("val")); 
       con.commit(); 
       synchronized(semaphore){ 
       semaphore.notify(); 
       } 
      }catch(Exception e){ 
       e.printStackTrace(); 
      } 
     } 
    }; 
    Thread t1 = new Thread(thread1); 
    Thread t2 = new Thread(thread2); 
    t1.start(); 
    t2.start(); 
    t1.join(); 
    t2.join(); 
} 

結果は次のようになります セッション1 NEXTVALは、次のとおりです。47 セッション2のnextvalがある:48 セッション1のCURRVALがある:47

関連する問題