在同一语句中获取插入的id

有没有办法在一个表中插入一行并获得新生成的ID,只在一个语句中? 我想使用JDBC,ID将由序列生成,或者是自动增量字段。

谢谢你的帮助。

约翰波兰克雷

使用getGeneratedKeys():

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

您可以使用RETURNING子句获取已更新或插入的任何列的值。 它适用于触发器(即:您获得在执行触发器后实际插入的值)。 考虑:

 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 

实际上,我认为nextval后面的currval确实有效。 这里有一些代码用两个线程来模拟这种行为,一个首先执行nextval,然后是一个currval,而另一个线程执行nextval。

 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(); } 

结果如下:Session1 nextval是:47 Session2 nextval是:48 Session1 currval是:47

我无法评论,否则我会加入Vinko Vrsalovic的post:

 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后更新de sequence是一个自治事务。 否则,另一个会话将从序列中获得相同的值。 因此,如果anothers sesssion已从insert和select之间的序列中选择,则获取currval将不会获得插入的id。

问候,Rob

直到执行INSERT之后才知道自动生成的ID的值,因为其他语句可以同时执行,并且RDBMS可以决定如何安排哪一个先行。

您在INSERT语句中的表达式中调用的任何函数都必须在插入新行之前进行求值,因此无法知道生成的ID值。

我可以想到两个接近你所要求的选项:

  • 编写一个运行AFTER INSERT的触发器,这样您就可以访问生成的ID键值。

  • 编写一个包装插入的过程,这样就可以在过程中执行其他代码并查询最后生成的ID。

但是,我怀疑你真正问的是,即使其他会话也在插入行并生成自己的ID值,您是否可以查询当前会话的最后生成的ID值。 您可以放心, 每个提供自动增量function的RDBMS都提供了一种查询此值的方法 ,它会告诉您当前会话范围中生成的最后一个ID。 这不受在其他会话中完成的插入的影响。

序列生成的id可以通过获得

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

在同一个事务中运行以获得一致的视图。

我想你会觉得这很有帮助:

我有一个自动递增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)); 

源: 线程:从插入返回值时出现Oracle / JDBC错误

我无法评论,否则我会刚刚添加到dfa的post中,但以下是直接JDBC的此function的示例。

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

但是,如果你使用像Spring这样的东西,它们会为你掩盖很多血腥的细节。 如果可以提供任何帮助,那就是Spring第11章,这是JDBC的细节。 使用它给我带来了很多麻烦。