多行 INSERT 与重复调用 PreparedStatement.executeUpdate()
Posted
技术标签:
【中文标题】多行 INSERT 与重复调用 PreparedStatement.executeUpdate()【英文标题】:Multi-row INSERT vs. repeatedly calling PreparedStatement.executeUpdate() 【发布时间】:2013-08-01 04:07:13 【问题描述】:如果我有一个使用以下架构创建的表:
CREATE TABLE names (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR);
还有一个List<String> names
我想添加到表中的名称,我看到了两种解决方法。
简单的蛮力解决方案是手动构造 SQL,如下所示:
String sql = "INSERT INTO names (name) VALUES ("+
Joiner.on("), (").join(names)+
");";
conn.createStatement().execute(sql);
这仅在 DB 中出现一次,并且看起来直观且直接。我知道存在 SQL 注入问题,但为了这个问题,我们假设这些问题已经得到解决。
替代方法是使用准备好的语句,然后 JDBC docs suggest 重复执行该语句,如下所示:
con.setAutoCommit(false);
PreparedStatement addNames = con.prepareStatement(
"INSERT INTO names (name) VALUES (?);");
for (String name : names)
addNames.setString(1, name);
addNames.executeUpdate();
con.commit();
con.setAutoCommit(true);
这样重复执行PreparedStatement
真的比简单地构造查询String并直接执行更可取吗?
【问题讨论】:
许多与性能相关的问题的问题在于它们过于理论化。一个人没有表,没有要插入的数据,没有要运行的单个查询,没有要处理的瓶颈,但由于某种原因,他突然遇到了一个问题——这更快。 为了更公平的比较,您应该 1) 将con.commit()
移出循环并 2) 使用批量更新(尽管它取决于驱动程序和数据库是否具有不同的性能)
JDBC 文档中的示例在循环中有con.commit();
,所以这就是我这样做的原因。同样对在循环中进行提交持怀疑态度。
@YourCommonSense 我不同意 - 向数据库发出 O(n)
请求并不是“不必要的理论”,它对于可扩展的应用程序来说是一个至关重要的问题。在我看来,最佳安全实践(使用 PreparedStatement)与最佳可扩展性实践(最小化数据库调用)背道而驰,我试图了解适当的平衡在哪里。
【参考方案1】:
还有两个选择:
使用PreparedStatement.addBatch()
。对于许多数据库,这将减少服务器往返次数。但并非适用于所有数据库(例如,不适用于 H2 数据库)。
使用PreparedStatement
,但多行,批量:
INSERT INTO names (name) VALUES (?), (?), (?), (?), (?), (?), (?), (?);
第二个应该减少所有数据库的服务器往返,但它有点复杂。
【讨论】:
谢谢,由于某种原因,我错过或误解了addBatch()
/executeBatch
,做更多的挖掘是非常有意义的,这正是我想要的。【参考方案2】:
是的,它更快 因为每次java应用程序向数据库发送一条新的SQL语句时,服务器都会检查语法错误,准备执行该语句的计划并执行。
如果再次发送相同的语句,尽管数据库服务器会检查它是否已经收到与它完全相同的语句。如果是这样,服务器不会检查其语法并为其准备执行计划,因此服务器只会执行它。
为了利用这个数据库特性,java 提供了prepared statement 的使用。这个特性允许你发送发送语句到数据库服务器,通过接受发送给它的参数值来重复执行。这改进了数据库性能,因为数据库服务器只需检查语法并为每个语句准备一次执行计划。
【讨论】:
我想更大的瓶颈将是服务器和客户端之间的来回,而不是验证时间。根据您的描述,这两个语句都经过一次验证,因此PreparedStatement
不需要多次验证这一事实似乎并没有帮助,因为天真的解决方案首先只有一个查询要运行。 ..以上是关于多行 INSERT 与重复调用 PreparedStatement.executeUpdate()的主要内容,如果未能解决你的问题,请参考以下文章
如何在oracle 11g中使用一个INSERT语句在一列中插入多行[重复]
INSERT INTO .. ON DUPLICATE KEY更新多行记录
如何在不重复声明的“INSERT INTO dbo.Blah”部分的情况下插入多行?