多个预处理语句的 JDBC 批处理

时间:2021-04-26 16:44:49

标签: postgresql jdbc prepared-statement

是否可以将来自多个 JDBC 准备好的语句的提交批处理在一起?

在我的应用程序中,用户将插入一条或多条记录以及相关表中的记录。例如,我们需要更新“contacts”表中的一条记录,删除“tags”表中的相关记录,然后插入一组新的标签。

UPDATE contacts SET name=? WHERE contact_id=?;
DELETE FROM tags WHERE contact_id=?;
INSERT INTO tags (contact_id,tag) values (?,?);
// insert more tags as needed here...

这些语句需要成为单个事务的一部分,我想在到服务器的单次往返中完成它们。

要在单次往返中发送它们,有两种选择:为每个命令创建一个 Statement 然后调用 .addBatch(),或者为每个命令创建一个 PreparedStatement,然后调用 {{ 1}}、.setString() 等用于参数值,然后调用 .setInt()

第一种选择的问题在于,在 ..addBatch() 调用中发送完整的 SQL 字符串效率低下,而且您无法从经过清理的参数输入中获益。

第二种选择的问题在于它可能不保留 SQL 语句的顺序。例如,

addBatch()

在上面的代码中,是否可以保证所有语句都按照我们调用的 Connection con = ...; PreparedStatement updateState = con.prepareStatement("UPDATE contacts SET name=? WHERE contact_id=?;"); PreparedStatement deleteState = con.prepareStatement("DELETE FROM contacts WHERE contact_id=?;"); PreparedStatement insertState = con.prepareStatement("INSERT INTO tags (contact_id,tag) values (?,?);"); updateState.setString(1, "Bob"); updateState.setInt(1, 123); updateState.addBatch(); deleteState.setInt(1, 123); deleteState.addBatch(); ... etc ... ... now add more parameters to updateState, and addBatch()... ... repeat ... con.commit(); 的顺序执行,即使是在不同的准备好的语句中?排序显然很重要;我们需要在插入新标签之前删除标签。

我还没有看到任何说明将为给定连接保留语句顺序的文档。

我正在使用 Postgres 和默认的 Postgres JDBC 驱动程序(如果有的话)。

1 个答案:

答案 0 :(得分:1)

批处理是每个语句对象,因此每个 executeBatch() 调用对 StatementPreparedStatement 对象执行一个批处理。换句话说,这仅执行与该语句对象的批处理关联的语句(或值集)。不可能跨多个语句对象“排序”执行。在单个批次中,订单被保留。

如果您需要按特定顺序执行语句,则需要按该顺序显式执行它们。这要么意味着对每个值集单独调用 execute(),要么使用单个 Statement 对象并即时生成语句。由于 SQL 注入的可能性,不推荐使用最后一种方法。