2011-02-10 9 views
5

Oracleを初めて使用しているので、すでに回答済みのものはthis SO questionになります。私はちょうどそれを働かせるように見えない。ここで私が使用しているの文です:JDBCを使用してOracle 11gで最後の挿入IDを取得

declare 
    lastId number; 
begin 
INSERT INTO "DB_OWNER"."FOO" 
    (ID, DEPARTMENT, BUSINESS) 
    VALUES (FOO_ID_SEQ.NEXTVAL, 'Database Management', 'Oracle') 
    RETURNING ID INTO lastId; 
end; 

私は私が作ったというのPreparedStatement executeQueryを呼び出し、それがうまくデータベースにすべてを挿入します。しかし、私はIDを取得する方法を把握していないようです。返されたResultSetオブジェクトは私のためには機能しません。

if(resultSet.next()) ... 

読み取り厄介なのSQLExceptionは、利回り呼び出す:

PLSQL文でフェッチを実行できません:私はlastIdことを取得するにはどうすればよい

次の?明らかに私はそれを間違っている。

+0

いつでも 'SELECT FOO_ID_SEQ.CURRVAL FROM DUAL'をクエリできます。 – Phil

+2

関数またはストアドプロシージャをポストする - あなたがINOUTパラメータとして 'lastid'を設定したかどうかを知る必要があります。 –

+0

別のクエリを実行する必要がある場合は、挿入したばかりの要素のIDであるとは限りません。そこに忍び込んでいる別のクエリが存在する可能性があります。 – geowa4

答えて

2

(プロシージャではなく)それをあなたに返す関数にします。または、OUTパラメータを持つプロシージャを使用します。

1

文を準備するときは、2番目のパラメータをRETURN_GENERATED_KEYSに設定します。次に、ステートメントオブジェクトからResultSetを得ることができるはずです。

+0

これはスレッドセーフですか? –

+0

@James、これはおそらく同じキーとステートメントで動作する複数のスレッドを持つべきではないので、奇妙な質問のように思えます。あなたはあなたの質問を拡大できますか? – jzd

+0

確かに。 1つのDAOインスタンス(シンクロナイズされていない)と複数の人がデータベース(ある種のサーバーアプリケーション)で作業している場合、これは信頼性の低い動作を生成します。私は、データベースが先着順でこの値を返すと仮定していますので、それは単一のユーザーアプリに適していますか?私は、Hibernateの 'EntityManager'が、プロキシパターンやそれらの行に沿った何かを使って、状態(持続されているかどうか)に関する問題を処理すると思います。 –

1

これはストアドプロシージャで実行していますか?このOracle documentによれば、サーバー側のドライバでは動作しません。

declare 
    lastId OUT number; 

があなたの声明を切り替えます

はあなたの宣言に変更し

...

The Oracle server-side internal driver does not support 
the retrieval of auto-generated keys feature.
2

私は何のOracleの私のすべてのコンピュータをパージしましたので、これは、動作するかどうかわからしかしありませんあなたの接続上でprepareCall()を使ってPreparedStatementからCallableStatementに渡します。次に、あなたの呼び出しの前に、出力パラメータを登録し、更新後にそれを読む:

cstmt.registerOutParameter(1, java.sql.Types.NUMERIC); 
cstmt.executeUpdate(); 
int x = cstmt.getInt(1); 
+1

文は変数 '?'を含んでいなくても動作します:DECLAREセクションを削除し、 'RETURNING ID INTO lastId'を' RETURNING ID INTO? 'に置き換えてください。また 'getInt'はintを返します:) –

+0

ありがとうございました。xの型をbyteからintに変更しました。 –

1

これを行うには、Statement.getGeneratedKeys()を使用することができます。 、

Connection conn = ... 
PreparedStatement pS = conn.prepareStatement(sql, new String[]{"id"}); 
pS.executeUpdate(); 
ResultSet rS = pS.getGeneratedKeys(); 
if (rS.next()) { 
    long id = rS.getLong("id"); 
    ... 
} 

あなたはこれでRETURNING x INTOものを行う必要はありません:あなたはちょうどあなたが戻って、このようなここConnection.prepareStatement過負荷などそのための方法のオーバーロード、のいずれかを使用して何をしたいの列JDBCを伝えることを確認する必要があります必要な基本的なSQL文を使用してください。

+1

long id = rS.getLong( "id");間違っています - 名前の代わりに列インデックスを使用する必要があります(oracleを使用) – Fisher

+0

@Fisher:Oracleでこのテクニック(列名を使用)を使用していました。たぶん、オラクルの状況/バージョン/構成には問題はありません。 – ColinD

2

Oracleドライバv11.2.0.3.0で試しました(10.xと11.1.xにいくつかのバグがありますので、other blogを参照してください)。以下のコードは正常に動作します:

final String sql = "insert into TABLE(SOME_COL, OTHER_COL) values (?, ?)"; 
PreparedStatement ps = con.prepareStatement(sql, new String[] {"ID"}); 
ps.setLong(1, 264); 
ps.setLong(2, 1); 
int executeUpdate = ps.executeUpdate(); 
ResultSet rs = ps.getGeneratedKeys(); 
if (rs.next()) { 
    // The generated id 
    long id = rs.getLong(1); 
    System.out.println("executeUpdate: " + executeUpdate + ", id: " + id); 
} 
関連する問題