Prepared Statement를 여러 번 재사용
풀 없이 단일 공통 연결로 Prepared Statement를 사용하는 경우 준비된 스테이트먼트의 성능을 가진 모든 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<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;
}
}
}
}
코드의 루프는 지나치게 단순화된 예에 불과합니다.
를 작성하는 것이 좋습니다.PreparedStatement
루프에서 반복해서 재사용할 수 있습니다.
(프로그램 플로우가 너무 복잡하기 때문에) 이것이 불가능한 상황에서는PreparedStatement
단 한 번만 사용해도 작업(SQL 파싱 및 실행 계획 캐싱)의 서버 측에서는 계속 줄어들기 때문입니다.
Java 측을 재사용하려는 상황에 대처하려면PreparedStatement
일부 JDBC 드라이버(Oracle 등)에는 다음과 같은 캐싱 기능이 있습니다.를 작성하는 경우PreparedStatement
동일한 연결상의 동일한 SQL에 대해 동일한(캐시된) 인스턴스를 제공합니다.
멀티스레딩에 대해서:어쨌든 JDBC 접속은 여러 스레드(즉, 여러 스레드에서 동시에 사용) 간에 공유할 수 없다고 생각합니다.각 스레드는 풀에서 자체 연결을 가져와서 사용하고 다시 풀로 반환해야 합니다.
언급URL : https://stackoverflow.com/questions/2467125/reusing-a-preparedstatement-multiple-times
'programing' 카테고리의 다른 글
1을 포함하는 어레이를 작성하는 방법...n (0) | 2022.10.15 |
---|---|
$http의 각 IE 캐싱 문제 (0) | 2022.10.15 |
생성자에 인수가 있는 Java 8 공급업체 (0) | 2022.10.06 |
DATE 또는 DATETIME 기본값을 설정할 때 MySQL에서 오류가 발생함 (0) | 2022.10.06 |
왜 PHP의 함수와 메서드는 대소문자를 구분하지 않는가? (0) | 2022.10.06 |