在没有连接池的情况下在单个连接中使用PreparedStatements时,开发人员经常面临创建新语句的困境每个 DML/SQL 操作的实例或重用现有实例。在这里,我们分析了两种方法的优缺点,并探索了一种提高效率和可扩展性的替代解决方案。
第一种方法涉及为每个操作重新创建一个新的PreparedStatement实例,确保每个语句都没有先前执行的任何残留参数或状态。然而,这种方法可能会导致性能下降,尤其是在多线程环境中。
第二种方法通过重用单个PreparedStatement实例来解决这些问题,并在每次执行之前清除其参数。虽然这种方法效率更高,但缺乏第一种方法的优雅和简单性。
执行多个 DML/SQL 操作的更优化解决方案是采用批处理。该技术涉及收集一系列操作并将它们作为对数据库的单个请求来执行。批处理显着减少了创建和关闭多个PreparedStatement实例的开销。
<code class="java">public void executeBatch(List<Entity> entities) throws SQLException { try ( Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement(SQL); ) { for (Entity entity : entities) { statement.setObject(1, entity.getSomeProperty()); // ... statement.addBatch(); } statement.executeBatch(); } }</code>
在执行批处理数量过多的场景下,限制批处理大小可以进一步提升性能。
<code class="java">public void executeBatch(List<Entity> entities) throws SQLException { try ( Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement(SQL); ) { int i = 0; for (Entity entity : entities) { statement.setObject(1, entity.getSomeProperty()); // ... statement.addBatch(); i++; if (i % 1000 == 0 || i == entities.size()) { statement.executeBatch(); // Execute every 1000 items. } } } }</code>
通过在同一个方法块中使用 try-with-resources 语句来获取和关闭连接以及PreparedStatement,可以缓解线程安全问题:
<code class="java">try ( Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement(SQL); ) { // ... }</code>
在事务场景中,禁用连接上的自动提交,仅在所有批次完成后提交事务,以确保数据一致性。
<code class="java">public void executeBatch(List<Entity> entities) throws SQLException { try (Connection connection = dataSource.getConnection()) { connection.setAutoCommit(false); try (PreparedStatement statement = connection.prepareStatement(SQL)) { // ... try { connection.commit(); } catch (SQLException e) { connection.rollback(); throw e; } } } }</code>
通过利用批处理执行并遵守正确的连接管理技术,开发人员可以利用PreparedStatements的强大功能,同时最大限度地提高效率和可扩展性,即使在多线程环境中也是如此。
以上是ReadyStatement重用:重用还是不重用?深入探讨效率和可扩展性的详细内容。更多信息请关注PHP中文网其他相关文章!