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

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

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

 public void executeBatch(List 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 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, как показано в выше fragmentов.

Если эти партии являются транзакционными, вы хотите отключить автосообщение соединения и только совершить транзакцию, когда все партии будут завершены. В противном случае это может привести к созданию грязной базы данных, когда первая партия пакетов будет успешной, а позже – нет.

 public void executeBatch(List 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 только один раз и повторно использовать его снова и снова в цикле.

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

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

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

Давайте будем гением компьютера.