使用 JDBC 获取 Oracle 11g 的最后插入 ID
Posted
技术标签:
【中文标题】使用 JDBC 获取 Oracle 11g 的最后插入 ID【英文标题】:Get last insert id with Oracle 11g using JDBC 【发布时间】:2011-06-24 13:08:33 【问题描述】:我是使用 Oracle 的新手,所以我将放弃之前在 this SO question 中已经回答的内容。我似乎无法让它工作。这是我正在使用的语句:
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
?显然我做错了。
【问题讨论】:
您可以随时查询SELECT FOO_ID_SEQ.CURRVAL FROM DUAL
。
发布函数或存储过程 -- 需要知道是否将lastid
设置为INOUT参数。
如果我必须执行另一个查询,我不能保证它是我刚刚插入的元素的 id。那里可能还有另一个查询。
CURRVAL
是会话安全的,但 RETURNING
子句允许您在一个语句中做两件事。
@OMGPonies 崭露头角的 Oracle 开发人员可以体验到的最大“灯泡”时刻之一 ;)
【参考方案1】:
使它成为一个返回给你的函数(而不是一个过程)。或者,有一个带有 OUT 参数的过程。
【讨论】:
【参考方案2】:不确定这是否可行,因为我已经清除了所有计算机中的任何 Oracle,但是...
将您的声明更改为:
declare
lastId OUT number;
通过在您的连接上使用 prepareCall() 将您的语句从 PreparedStatement 切换到 CallableStatement。然后在调用前注册输出参数,更新后读取:
cstmt.registerOutParameter(1, java.sql.Types.NUMERIC);
cstmt.executeUpdate();
int x = cstmt.getInt(1);
【讨论】:
这应该可以,尽管语句必须包含变量?
:删除 DECLARE 部分,并将@987654324@ 替换为RETURNING ID INTO ?
。 getInt
也返回一个 int :)
谢谢 - 将 x 的类型从 byte 更改为 int。【参考方案3】:
我尝试使用 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);
【讨论】:
【参考方案4】:准备语句时,将第二个参数设置为RETURN_GENERATED_KEYS
。然后你应该能够从语句对象中得到一个ResultSet
。
【讨论】:
@James,可能,但这似乎是一个奇怪的问题,因为您真的不应该让多个线程使用相同的键和语句。你能扩展你的问题吗? 当然。如果您有一个 DAO 实例(未同步)并且有多个人在处理数据库(某种服务器应用程序),这将产生不可靠的行为。我假设数据库以先到先得的方式返回此值,那么它是否适合单用户应用程序?我想 Hibernate 的EntityManager
使用代理模式或类似的方式处理状态(持久或不持久)的任何问题。【参考方案5】:
您可以使用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语句。
【讨论】:
long id = rS.getLong("id");错了 - 您必须使用列索引,而不是名称(使用 oracle) @Fisher:我绝对是在 Oracle 中使用这种技术(使用列名)。也许在 Oracle 的某些情况/版本/配置中它不起作用。【参考方案6】:你是在存储过程中这样做的吗?根据这个Oracle document,它不适用于服务器端驱动程序。
Oracle服务器端内部驱动不支持 检索自动生成的密钥功能。
【讨论】:
以上是关于使用 JDBC 获取 Oracle 11g 的最后插入 ID的主要内容,如果未能解决你的问题,请参考以下文章
oracle 11g - 在oracle 11g数据库中获取标识列的最后一个插入ID的方法是什么?
转: Maven 仓库中添加Oracle JDBC驱动(11g)