我正在回答我自己的问题,但我认为这不是一个好的答案 :) 我正在做的是一种混合。可以从 jdbi 动态运行 PL/SQL 块。从技术上讲,这是我所要求的来自 Java,而不是通过存储过程。但是,在我看来,这是一种 hack——在这种情况下,为什么不只创建存储过程(如果我没有找到更好的解决方案,我可能会这样做)。但是,对于信息,而不是:
String sql = "update foo set status = 1 where rownr in (select rownr from (select rownr from foo where runid = :runid and status = 0 order by rownr) where rownum = 1)";
return jdbi.withHandle((handle) -> {
handle
.createUpdate(sql)
.bind("runid", runId)
.executeAndReturnGeneratedKeys("rownr")
.mapTo(Integer.class)
.findOnly();
});
你可以的
String sql = "declare\n" +
"vRownr foo.rownr%type;\n" +
"begin\n" +
"update foo set status = 1 where rownr in (select rownr from (select rownr from foo where runid = :runid and status = 0 order by rownr) where rownum = 1) returning rownr into vRownr;\n" +
":rownr := vRownr;\n" +
"end;";
return jdbi.withHandle((handle) -> {
OutParameters params = handle
.createCall(sql)
.bind("runid", runId)
.registerOutParameter("rownr", Types.INTEGER)
.invoke();
return params.getInt("rownr");
});
就像我说的,在这种情况下最好只创建过程,但如果我猜你需要,它确实让你可以选择在 java 中动态构建 SQL。
基于this question,通过cmets 中的@APC 链接,可以使用不带declare/begin/end 的OracleReturning 类。
String sql = "update foo set status = 1 where rownr in (select rownr from (select rownr from foo where runid = ? and status = 0 order by rownr) where rownum = 1) returning rownr into ?";
return jdbi.withHandle((handle) -> {
handle
.createUpdate(sql)
.bind(0, runId)
.addCustomizer(OracleReturning.returnParameters().register(1, OracleTypes.INTEGER))
.execute(OracleReturning.returningDml())
.mapTo(Integer.class)
.findOnly();
});
但是,OracleReturning 不支持命名参数,因此您必须使用位置参数。由于我在普通 JDBC 上使用 JDBI 的主要原因是获得命名参数支持,这对我来说很重要,所以我不确定我会走哪条路
非常依赖它是您调用的 Oracle DB...
更新:OracleReturning 中命名参数的增强已合并到 master,并将包含在 3.1.0 版本中。感谢@qualidafial 的补丁