java - 多次重用 PreparedStatement

标签 java jdbc prepared-statement

在将 PreparedStatement 与没有任何池的单个公共(public)连接一起使用的情况下,我可以为每个 dml/sql 操作重新创建一个实例,以保持预准备语句的功能吗?

我的意思是:

for (int i=0; i<1000; i++) {
    PreparedStatement preparedStatement = connection.prepareStatement(sql);
    preparedStatement.setObject(1, someValue);
    preparedStatement.executeQuery();
    preparedStatement.close();
}

代替:

PreparedStatement preparedStatement = connection.prepareStatement(sql);
for (int i=0; i<1000; i++) {
    preparedStatement.clearParameters();
    preparedStatement.setObject(1, someValue);
    preparedStatement.executeQuery();
}
preparedStatement.close();

我的问题是我想把这段代码放到多线程环境中,你能给我一些建议吗?谢谢

最佳答案

第二种方法效率更高,但更好的方法是批量执行它们:

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();
    }
}

但是,您一次可以执行多少个批处理取决于 JDBC 驱动程序的实现。例如,您可能希望每 1000 个批处理执行一次:

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.
            }
        }
    }
}

对于多线程环境,如果按照正常的JDBC习语,在同一方法 block 内尽可能短的范围内获取和关闭连接和语句,则无需担心使用 try-with-resources声明如上面的片段所示。

如果这些批处理是事务性的,那么您希望关闭连接的自动提交,并且仅在所有批处理完成后才提交事务。否则可能会导致前一批批成功后一批批不成功,导致数据库脏。

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;
            }
        }
    }
}

关于java - 多次重用 PreparedStatement,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2467125/

相关文章:

java - 使用扫描仪读取文件时出现InputMismatchException

java - 我的 Android 应用程序与巨大的 MS Access 数据库的 Ucanaccess 连接在 Android 设备上占用了过多的堆空间。还有其他选择吗?

java - 在 Java 中将 sqlite 从磁盘备份和恢复到内存

php - 如何使用准备好的语句删除列?

java - 存储过程和准备语句错误

java - Android Volley - 检查互联网状态

java - 字符串串行通信

java - 在java中解析vagrant文​​件

java - JBDC - 跨并发线程以原子方式执行 SELECT 和 INSERT

java - 在 JAVA 中为 MySQL PreparedStatment 绑定(bind) NULL?