java - 使用 jdbi 进行更新时获取更新行的主键

标签 java sql oracle jdbc jdbi

我正在使用jdbi(但如果需要的话准备使用原始jdbc)。我的数据库目前是Oracle。我有一个更新,可以更新符合特定条件的第一行。我想从同一语句中获取更新行的主键。这可能吗?

我试过了

Integer rowNum = handle
                    .createUpdate(sqlFindUpdate)
                    .bind("some var", myVal)
                    .executeAndReturnGeneratedKeys("id")
                    .mapTo(Integer.class)
                    .findOnly();

但我猜这不是生成的 key ,因为它没有找到它(非法状态异常,但更新成功)。

基本上,我在数据库中有一个需要处理的项目列表。所以,我想获取下一个并同时将其标记为“正在进行”。我希望能够支持多个工作线程,因此它需要是单个语句 - 我无法在(状态已更改,因此不再匹配)之后执行选择并在引入竞争之前执行此操作情况。

我想我可以做一个使用返回的存储过程,但我可以直接从java来做吗?

最佳答案

我正在回答我自己的问题,但我认为这不是一个好的答案:)我正在做的事情是一种混合。可以从 jdbi 动态运行 PL/SQL block 。从技术上讲,正如我所要求的,这是来自 Java,而不是通过存储过程。然而,在我看来,这是一种黑客行为 - 在这种情况下,为什么不直接创建存储过程(如果我找不到更好的解决方案,我可能会这样做)。但是,作为信息,而不是:

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正如注释中的 @APC 所链接的,可以使用 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 不支持命名参数,因此您必须使用位置。由于我使用 JDBI 而不是普通 JDBC 的主要原因是获得命名参数支持,这对我来说很重要,所以我不确定该走哪条路

非常依赖它作为您正在调用的 Oracle DB...

更新:OracleReturning 中命名参数的增强已合并到 master,并将包含在 3.1.0 版本中。感谢 @qualidafial 的补丁

关于java - 使用 jdbi 进行更新时获取更新行的主键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48361387/

相关文章:

java - 如何正确关闭 Tomcat 上的 JAX-WS Spring 应用程序?

Java - 如何以编程方式从打开新选项卡的 URL 下载附件?

php - 批量插入行终止符问题

sql - 我可以在 Oracle SQL 中组合多个列的一部分吗

Java Singleton.getInstance() 返回空值?

java - 创建嵌套列表

mysql - 正向工程错误 1054 MySQL 研讨会

sql - 如何删除SQL中的多个值?

oracle - CREATE TABLE 和 CREATE ANY TABLE 权限的区别

oracle - 显示来自 oracle 10g 存储过程的结果集