【问题标题】:Get primary keys of updated rows when doing an update with jdbi使用 jdbi 进行更新时获取更新行的主键
【发布时间】:2018-01-20 21:41:08
【问题描述】:

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

我试过了

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

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

基本上,我在数据库中有一个需要处理的项目列表。所以,我想同时获得下一个并将其标记为“进行中”。我希望能够支持多个工作线程,所以它需要是一个语句 - 我不能在之后进行选择(状态已经改变,所以它不再匹配)并且在引入比赛之前做条件。

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

【问题讨论】:

标签: java sql oracle jdbc jdbi


【解决方案1】:

我正在回答我自己的问题,但我认为这不是一个好的答案 :) 我正在做的是一种混合。可以从 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 的补丁

【讨论】:

  • 似乎可以使用 JDBC 检索生成的密钥。查看this StackOverflow thread。所以这就变成了如何在 JDBI 中做到这一点的问题。文档建议this can be done
  • 问题是,更新(与插入相反-JDBI 对两者都使用“更新”类型)不是真正的生成 键,而是匹配键。但感谢@APC 的链接,它有所帮助。查看我的更新
  • 请打开一个 Jdbi 问题以支持 OracleReturning 中的命名参数。应该不会太难。
  • 好主意@qualidafial。 github.com/jdbi/jdbi/issues/1022 尽管缺少命名参数,我最终还是选择了 OracleReturning 路线
  • 后续:OracleReturning中命名参数的增强已合并到master,将包含在3.1.0版本中
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-08
  • 2019-05-21
  • 1970-01-01
  • 1970-01-01
  • 2019-06-22
  • 2019-04-23
  • 2023-03-26
相关资源
最近更新 更多