【问题标题】:Batch update in Postgresql JDBC driver rolls back in autocommitPostgresql JDBC 驱动程序中的批量更新在自动提交中回滚
【发布时间】:2015-04-07 06:36:11
【问题描述】:

我正在使用 postgres 9.3-1100-jdbc41 JDBC4 驱动程序进行批量插入。

根据 JDBC 规范,它的 up 向应用程序禁用自动提交并提交或 回滚事务。

在我的情况下,我没有使用任何事务(即自动提交为真),但如果批处理中的一个插入失败,插入仍然会回滚。

根据 JDBC 规范“如果批量更新中的某个命令未能正确执行,此方法会抛出一个 BatchUpdateException,并且 JDBC 驱动程序可能会或可能不会继续处理剩余的命令 在批处理中。”。这里并没有说之前执行的命令会被回滚。

我的理解错了吗?如果不是,为什么驱动程序会以这种方式行事,如果是,那么根据规范,正确的行为是什么。

【问题讨论】:

  • 如果你使用自动提交,如果我没记错的话,所有批量插入仍然在一个事务中完成。将其视为编写插入多行的单个插入的不同方式 (insert into .. values (..),(..),(..),(..))
  • 感谢您的回复。但是规范呢。我认为这只是为了避免每次插入的网络往返,并且应用事务应该取决于应用程序。在数据库上,每个插入都应作为一个单元执行。作为用户,我可以在单个批次中添加不相关的插入以避免往返,如果某些命令失败,则不应回滚。
  • 规范说“可能会或可能不会继续处理” - Postgres 选择不继续。
  • 规范说“可能会或可能不会继续处理进一步的命令”我也找到了这个链接,但它太旧了,postgresql.org/message-id/…
  • 那么“可能继续”有什么不清楚的地方?

标签: java postgresql jdbc batch-updates


【解决方案1】:

据我所知,规范基本上把这留给了司机;如果批处理失败,它没有指定是否提交已经处理的工作。

PgJDBC 在事务中执行批处理,因此如果批处理的任何部分失败,那么它将全部中止。

如果您觉得这种行为不正确,您需要做的第一件事是编写一个测试用例,证明其他驱动程序的行为始终与 PgJDBC 不同,并将其提交给the PgJDBC issue tracker。我们没有时间研究其他驱动程序的行为,因此您需要编写测试用例并在其他流行的数据库(MS SQL Server、Oracle、DB2、MySQL 等)上运行它或安排让它由别人运行。如果您表明 PgJDBC 的行为与其他驱动程序处理批处理的方式不同,那么值得考虑添加一个选项来更改行为(并最终使其成为默认行为)。

【讨论】:

  • 我不认为你可以改变驱动程序的行为——毕竟如果一个语句失败,Postgres 本身不允许提交事务。例如,这是不同的即使中间 DML 语句失败,您也可以提交事务的 Oracle。
  • @a_horse_with_no_name 如果需要,可以在这种情况下更改驱动程序的行为。 PreparedStatement 批次(这是我假设这个问题所涉及的)作为单个 Parse 消息在线发送,然后是多个 Bind/Describe/Execute 消息,每个批次条目一个。如果事务尚未打开,则以初始BEGIN 和结束COMMIT 打开一个事务。通过省略包装事务描述语句,在自动提交中执行此操作很简单。
  • @a_horse_with_no_name 不仅如此,v3 协议的行为也符合规范的要求。如果语句中有错误,Pg 将刷新流的其余部分,直到它遇到来自客户端的 Sync 消息。所以我们不必担心在错误后阻止后续语句的执行——这是规范允许的,但在实践中是一个可怕的想法。
  • @a_horse_with_no_name 因此,如果 OP 可以证明驾驶员当前行为不正确的令人信服的原因,我认为改变并不特别困难,除非我在某处遗漏了皱纹。
  • 伙计们,我忘了提到如果我们使用 Statement.RETURN_GENERATED_KEYS,成功的插入不会回滚。这件事增加了我的困惑。
猜你喜欢
  • 1970-01-01
  • 2013-10-25
  • 2012-12-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多