2011-02-10 84 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; 

當我打電話executeQuery PreparedStatement的把我所造的,這一切都插入到數據庫就好了。但是,我似乎無法弄清楚如何檢索ID。返回的ResultSet對象不適用於我。調用

if(resultSet.next()) ... 

產生一個討厭的SQLException,上面寫着:

無法執行取一個PLSQL聲明:下一

如何獲取lastId?很明顯,我做錯了。

+0

您可以隨時查詢'SELECT FOO_ID_SEQ.CURRVAL FROM DUAL'。 – Phil

+2

發佈函數或存儲過程 - 需要知道是否將'lastid'設置爲INOUT參數。 –

+0

如果我必須執行另一個查詢,我不能保證它是我剛剛插入的元素的id。那裏可能會有另一個查詢。 – geowa4

回答

2

使它返回給你(而不是一個過程)的函數。或者,有一個OUT參數的程序。

1

當您準備語句時,將第二個參數設置爲RETURN_GENERATED_KEYS。那麼你應該可以得到一個ResultSet關閉聲明對象。

+0

這是線程安全嗎? –

+0

@詹姆斯,可能但這似乎是一個奇怪的問題,因爲你真的不應該有多個線程使用相同的鍵和語句。你可以擴展你的問題嗎? – jzd

+0

當然。如果你有一個單獨的DAO實例(不同步)並且有多個人在數據庫上工作(某種服務器應用程序),這會產生不可靠的行爲。我假設數據庫以先到先得的方式返回這個值,那麼它會適合單個用戶應用程序嗎?我猜想Hibernate的EntityManager可以處理與狀態有關的任何問題(保存與否),使用代理模式或其他方式。 –

1

你是否在存儲過程中這樣做?根據這Oracle document,它不會與服務器端驅動程序一起使用。

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

不知道這會的工作,因爲我已經清除了我所有的東西甲骨文的電腦,但......

更改申報:

declare 
    lastId OUT number; 

切換您的發言通過在連接上使用prepareCall()從PreparedStatement轉換爲CallableStatement。然後呼叫之前註冊輸出參數,並在更新後閱讀:

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

這應該起作用,儘管語句必須包含一個變量'?':刪除DECLARE部分,並用'RETURNING ID INTO?'替換'RETURNING ID INTO lastId'。 'getInt'返回一個int :) –

+0

謝謝 - 將x的類型從字節改爲int。 –

1

您可以使用Statement.getGeneratedKeys()做到這一點。你只需要確保告訴JDBC你想回來使用該方法重載之一哪些列,如Connection.prepareStatement超載這裏:

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的東西與此,只需使用您想要的基本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); 
}