Postgresql 多个准备语句的JDBC批处理
是否可以将多个JDBC准备语句中的提交批处理在一起 在我的应用程序中,用户将插入一条或多条记录以及相关表中的记录。例如,我们需要更新“contacts”表中的记录,删除“tags”表中的相关记录,然后插入一组新的标记Postgresql 多个准备语句的JDBC批处理,postgresql,jdbc,prepared-statement,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
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...
这些语句需要是单个事务的一部分,我希望在到服务器的一次往返中完成它们
要在一次往返中发送它们,有两种选择:为每个命令创建一条语句,然后调用.addBatch()
,或为每个命令创建一条PreparedStatement
,然后调用.setString()
,.setInt()
等。对于参数值,然后调用.addBatch()
第一种选择的问题是,在.addBatch()调用中发送完整的SQL字符串效率低下,而且您无法获得经过净化的参数输入的好处
第二种选择的问题是它可能无法保持SQL语句的顺序。比如说,
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();
在上面的代码中,是否可以保证所有语句都将按照我们称为.addBatch()
的顺序执行,即使是在不同的准备语句之间?排序显然很重要;我们需要先删除标签,然后再插入新标签
我还没有看到任何文档说明将为给定的连接保留语句的顺序
我使用的是Postgres和默认的Postgres JDBC驱动程序,如果这很重要的话。批处理是针对每个语句对象的,因此批处理是根据
executeBatch()
调用语句或PreparedStatement
对象执行的。换句话说,这只执行与该语句对象的批处理相关联的语句(或值集)。不可能跨多个语句对象“排序”执行。在单个批次中,订单将保留
如果需要按特定顺序执行语句,则需要按该顺序显式执行它们。这意味着对每个值集分别调用execute()
,或者使用单个语句
对象并动态生成语句。由于SQL注入的潜力,不推荐最后一种方法。您永远不会在一次往返中完成所有这一切,因为提交本身,更不用说驱动程序在与数据库通信时所做的任何事情了,您对此一无所知,更不用说TCP在分段和确认段时所做的事情了。不管你怎么想,在任何情况下,一次往返都没有什么特别的好处。但是你在这里有一个严重的误解。在调用executeBatch()
之前,批处理中实际上不会发生任何事情。然后这一切都会发生,而且是按顺序发生的,但是您必须按照您定义的顺序对所有三个PreparedStatement
对象调用executeBatch()
:比如updateState.executeBatch();删除状态;executeBatch();insertState.executeBatch()代码>;首先进行所有更新,然后进行所有删除,然后进行所有插入。这是没有办法的。(当然,在提交之前,这一切都不会发生。)@user207421如果有多个子表(在我的例子中是7个,但会有更多),那么往返会产生很大的不同。假设每次往返的延迟为5毫秒,那么我们将每个父记录的延迟从5毫秒提高到35毫秒。如果你试图批量处理100条父记录,这是一件大事。局域网内的延迟是微不足道的。我到世界另一边的ping时间是8毫秒。您应该关注数据库操作的速度,它要长几个数量级:而不是像这样的琐事。尤其是不可实现的琐事。但很难理解为什么要更新要删除的行。