Повторное использование PreparedStatement несколько раз



в случае использования PreparedStatement с одним общим соединением без какого-либо пула, могу ли я воссоздать экземпляр для каждой операции 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();


мой вопрос возникает из-за того, что я хочу поместить этот код в многопоточную среду, можете ли вы дать мне несколько советов? спасибо

714   2  

2 ответов:

второй способ немного более эффективен, но гораздо лучший способ-выполнять их в пакетах:

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 с использованием 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;
            }
        }
    }
}

цикл в вашем коде-это только упрощенный пример, верно?

было бы лучше создать PreparedStatement только один раз, и повторно использовать его снова и снова в цикле.

в ситуациях, когда это невозможно (потому что это слишком усложнило поток программы), по-прежнему полезно использовать PreparedStatement, даже если вы используете его только один раз, потому что серверная часть работы (разбор SQL и кэширование плана выполнения) все равно будет уменьшенный.

чтобы устранить ситуацию, в которой вы хотите повторно использовать Java-side PreparedStatement, некоторые драйверы JDBC (например, Oracle) имеют функцию кэширования: если вы создадите PreparedStatement для того же SQL на том же соединении, он даст вам тот же (кэшированный) экземпляр.

о многопоточности: я не думаю, что соединения JDBC могут быть разделены между несколькими потоками (т. е. использоваться одновременно несколькими потоками) в любом случае.Каждый поток должен получить свое собственное соединение от бассейн, использовать его, и вернуть его в бассейн снова.

Comments

    Ничего не найдено.