Многократное использование 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();

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

95
задан BalusC 18 March 2010 в 02:12
поделиться

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;
            }
        }
    }
}
140
ответ дан 24 November 2019 в 05:51
поделиться

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

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

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

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

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

13
ответ дан 24 November 2019 в 05:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: