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.
}
}
}
}
マルチスレッド環境については、次のように、try-with-resourcesステートメントを使用した通常のJDBCイディオムに従って、同じメソッドブロック内の接続とステートメントを可能な限り最短の範囲で取得して閉じる場合、このことを心配する必要はありません。上記のスニペット。
これらのバッチがトランザクションの場合、接続の自動コミットをオフにし、すべてのバッチが終了したときにのみトランザクションをコミットします。そうしないと、最初のバッチのバッチが成功したときにデータベースがダーティになる可能性があり、その後のバッチは成功しません。
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;
}
}
}
}
sql
はループ内で変化しませんか?ループの反復ごとにクエリが変更されない場合、反復PreparedStatement
ごとに新しいコードを作成するのはなぜですか(最初のコードスニペット)。そうする理由はありますか?