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