programing

스테이트먼트와 Prepared 스테이트먼트의 차이

kingscode 2022. 9. 1. 23:49
반응형

스테이트먼트와 Prepared 스테이트먼트의 차이

준비 스테이트먼트는 스테이트먼트의 약간 더 강력한 버전으로 적어도 스테이트먼트만큼 빠르고 쉽게 처리할 수 있어야 합니다.
준비 스테이트먼트는 파라미터화할 수 있습니다.

대부분의 관계형 데이터베이스는 다음 4단계로 JDBC/SQL 쿼리를 처리합니다.

  1. 수신 SQL 쿼리 구문 분석
  2. SQL 쿼리 컴파일
  3. 데이터 수집 경로 계획/최적화
  4. 최적화된 쿼리 실행/취득 및 데이터 반환

스테이트먼트는 항상 데이터베이스로 전송되는 각 SQL 쿼리에 대해 위의 4단계를 수행합니다.준비 스테이트먼트는 위의 실행 프로세스에서 (1) - (3) 단계를 미리 실행합니다.따라서 Prepared 스테이트먼트를 작성할 때 몇 가지 사전 최적화가 즉시 수행됩니다.그 결과 실행 시 데이터베이스 엔진의 부하가 경감됩니다.

이제 제 질문은 다음과 같습니다.

"준비된 스테이트먼트를 사용하면 다른 장점이 있습니까?"

의 이점:

  • SQL 문의 사전 컴파일 및 DB 측 캐싱을 통해 전체적으로 실행 속도가 빨라지고 동일한 SQL 문을 일괄적으로 재사용할 수 있습니다.

  • 따옴표 및 기타 특수문자의 기본 이스케이프를 통해 SQL 주입 공격을 자동으로 차단합니다.이를 위해서는 다음 중 하나를 사용해야 합니다.PreparedStatement setXxx()값 설정 방법

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email, birthdate, photo) VALUES (?, ?, ?, ?)");
    preparedStatement.setString(1, person.getName());
    preparedStatement.setString(2, person.getEmail());
    preparedStatement.setTimestamp(3, new Timestamp(person.getBirthdate().getTime()));
    preparedStatement.setBinaryStream(4, person.getPhoto());
    preparedStatement.executeUpdate();
    

    따라서 문자열 연결을 통해 SQL 문자열의 값을 인라인하지 않습니다.

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email) VALUES ('" + person.getName() + "', '" + person.getEmail() + "'");
    preparedStatement.executeUpdate();
    
  • SQL 문자열에서 비표준 Java 개체(예: , , , Blob) 및()Clob를 쉽게 설정할 수 있습니다.이러한 타입의 대부분은, 「그냥」할 수 없습니다.toString()단순하게 하듯이Statement아래 유틸리티 방법으로 설명한 바와 같이 루프 내에서 이 모든 것을 사용할 수 있습니다.

    public static void setValues(PreparedStatement preparedStatement, Object... values) throws SQLException {
        for (int i = 0; i < values.length; i++) {
            preparedStatement.setObject(i + 1, values[i]);
        }
    }
    

    다음과 같이 사용할 수 있습니다.

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email, birthdate, photo) VALUES (?, ?, ?, ?)");
    setValues(preparedStatement, person.getName(), person.getEmail(), new Timestamp(person.getBirthdate().getTime()), person.getPhoto());
    preparedStatement.executeUpdate();
    
  1. 사전 컴파일(한 번)되므로 동적 SQL의 반복 실행 속도가 빨라집니다(파라미터 변경 시).

  2. 데이터베이스 스테이트먼트 캐싱으로 DB 실행 성능 향상

    데이터베이스는 이전에 실행된 문의 실행 계획 캐시를 저장합니다.이렇게 하면 데이터베이스 엔진은 이전에 실행된 문의 계획을 재사용할 수 있습니다.Prepared Statement는 파라미터를 사용하기 때문에 실행할 때마다 동일한 SQL로 표시되므로 데이터베이스는 이전 접근플랜을 재사용할 수 있어 처리를 줄일 수 있습니다.문은 매개 변수를 SQL 문자열에 "인라인"하므로 DB에 동일한 SQL로 표시되지 않으므로 캐시 사용을 방지합니다.

  3. 바이너리 통신 프로토콜을 통해 대역폭이 줄어들고 DB 서버에 대한 콜 전송 속도가 빨라집니다.

    준비된 문은 일반적으로 비 SQL 이진 프로토콜을 통해 실행됩니다.즉, 패킷내의 데이터가 적어지기 때문에, 서버와의 통신이 고속이 됩니다.일반적으로 네트워크 조작은 디스크 조작보다 몇 배 느리고 메모리 내 CPU 조작보다 몇 배 느립니다.따라서 네트워크를 통해 전송되는 데이터 양이 감소하면 전체 성능에 좋은 영향을 미칩니다.

  4. 제공된 모든 매개 변수 값에 대한 텍스트를 이스케이프하여 SQL 주입으로부터 보호합니다.

  5. 쿼리 코드와 파라미터 값을 (연결된 SQL 문자열에 비해) 더 잘 분리하여 가독성을 높이고 코드 유지자가 쿼리의 입력과 출력을 빠르게 이해할 수 있도록 지원합니다.

  6. Java에서는 getMetadata()와 getParameterMetadata()를 호출하여 각각 결과 세트필드와 파라미터 필드를 반영할 수 있습니다.

  7. 자바에서는 setObject, setBoolean, setByte, setDate, setDouble, setFloat, setInt, setLong, setShort, setTime, setTimestamp를 통해 Java 객체를 파라미터 유형으로 인텔리전트하게 받아들입니다(포맷()뿐만 아니라).

  8. Java에서는 setArray 메서드를 통해 SQL 어레이를 파라미터 유형으로 받아들입니다.

  9. 자바에서는 CLOB, BLOB, OutputStreams 및 Readers를 setClob/set을 통해 파라미터 "피드"로 받아들입니다.NClob, setBlob, setBinaryStream, setCharaciStream/setAsciStream/set각각 NcaracterStream 메서드

  10. Java에서는 DB 고유의 값을 SQL DATALINK, SQL ROWID, SQL XML 및 NULL로 설정할 수 있습니다.URL, setRowId, setSQLML 및 setNull 메서드

  11. Java에서는 Statement에서 모든 메서드를 상속합니다.addBatch 메서드를 상속하고 addBatch 메서드를 통해 일괄 처리된 SQL 명령어 세트와 일치하도록 파라미터 값 세트를 추가할 수 있습니다.

  12. Java에서는 특별한 유형의 PreparedStatement(CallableStatement 서브클래스)를 사용하여 저장 프로시저를 실행할 수 있습니다.고성능, 캡슐화, 프로시저 프로그래밍 및 SQL, DB 관리/유지보수/트위킹, DB 로직 및 자체 기능 사용을 지원합니다.

PreparedStatement는 SQL 주입 공격을 방지하는 데 매우 적합한 방어 수단입니다(단, 오류 방지 기능은 아닙니다).매개 변수 값을 바인딩하는 것은 "작은 Bobby 테이블"이 원치 않는 방문을 하지 않도록 보호하는 좋은 방법입니다.

스테이트먼트에 비해 Prepared Statement의 장점은 다음과 같습니다.

  1. Prepared Statement는 특수 문자를 자동으로 빠져나가므로 SQL 주입 공격을 방지하는 데 도움이 됩니다.
  2. PreparedStatement를 사용하면 파라미터 입력을 사용하여 동적 쿼리를 실행할 수 있습니다.
  3. PreparedStatement는 쿼리의 입력 파라미터를 설정하기 위한 다양한 유형의 세터 메서드를 제공합니다.
  4. Prepared Statement가 Statement보다 빠릅니다.PreparedStatement를 재사용하거나 여러 쿼리를 실행하기 위해 PreparedStatement의 배치 처리 방법을 사용하면 더 잘 볼 수 있습니다.
  5. PreparedStatement는 setter 메서드를 사용하여 객체 지향 코드를 작성하는 데 도움이 됩니다.또한 Statement에서는 쿼리를 작성하기 위해 String Connectation을 사용해야 합니다.설정할 파라미터가 여러 개 있는 경우 String 연결을 사용한 쿼리 작성은 매우 보기 흉하고 오류가 발생하기 쉽습니다.

SQL 주입 문제에 대한 자세한 내용은 http://www.journaldev.com/2489/jdbc-statement-vs-preparedstatement-sql-injection-example를 참조하십시오.

더 이상 추가할 것이 없습니다.

1 - 루프로 쿼리를 실행하는 경우(1회 이상) 최적화를 위해 준비된 스테이트먼트가 더 빠를 수 있습니다.

2 - 파라미터화된 쿼리는 SQL Injection을 피하는 좋은 방법입니다.파라미터화된 쿼리는 PreparedStatement에서만 사용할 수 있습니다.

문은 정적이고 준비된 문은 동적입니다.

문은 DDL에 적합하고 DML에 준비된 문입니다.

준비된 문은 더 빠르지만 문은 더 느립니다.

많은 차이점(표준)

스테이트먼트에서 CLOB를 수행할 수 없습니다.

그리고: (OraclePrepared Statement

mattjames가 인용한 바와 같이

BIND VARIAS를 받아들일 수 없는 유일한 스테이트먼트타입이기 때문에 JDBC에서의 스테이트먼트 사용은 DDL(ALTER, CREATE, GRANT 등)에 사용되도록 100% 현지화해야 합니다.기타 모든 유형의 스테이트먼트(DML, Query)에는 PreparedStatements 또는 CallableStatements를 사용해야 합니다.이는 바인드 변수를 받아들이는 문 타입이기 때문입니다.

이것은 사실, 규칙, 법입니다.어디서나 준비된 문구를 사용하세요.문장은 거의 아무 데도 사용하지 않습니다.

문은 정적 SQL 문을 실행하는 데 사용되며 입력 매개 변수를 수락할 수 없습니다.

Prepared Statement는 SQL 문을 여러 번 동적으로 실행하기 위해 사용됩니다.입력 파라미터를 받아들입니다.

sql 주입은 prepared 스테이트먼트에 의해 무시되므로 prepared 스테이트먼트의 보안이 강화됩니다.

  • 읽기 쉽다
  • 쿼리 문자열을 쉽게 상수로 만들 수 있습니다.

Statementinterface는 파라미터 없이 스태틱 SQL 문을 실행합니다.

PreparedStatementinterface(extending Statement)는 파라미터의 유무에 관계없이 미리 컴파일된 SQL 문을 실행합니다.

  1. 반복 실행 시 효율화

  2. 미리 컴파일되어 있기 때문에 고속입니다.

준비된 쿼리 또는 매개 변수화된 쿼리의 또 다른 특징: 이 문서에서 인용한 참조입니다.

이 문은 데이터베이스 시스템의 기능 중 하나로 동일한 SQL 문이 높은 효율로 반복적으로 실행됩니다.준비된 문장은 템플릿의 한 종류이며 다른 매개 변수를 가진 응용 프로그램에서 사용됩니다.

스테이트먼트 템플릿은 작성되어 데이터베이스 시스템 및 데이터베이스 시스템으로 전송되며, 이 템플릿에 대한 해석, 컴파일 및 최적화를 실행하지 않고 실행한다.

템플릿 작성 후 어플리케이션 중에 구가 전달되지 않는 등의 파라미터 중 일부는 데이터베이스 시스템에 이들 파라미터를 전송하고 데이터베이스 시스템은 SQL 문의 템플릿을 사용하여 요구에 따라 실행됩니다.

응용 프로그램이 서로 다른 기술과 프로토콜을 사용하여 매개 변수를 준비할 수 있으므로 준비된 문은 SQL Injection에 매우 유용합니다.

데이터 수가 증가하고 인덱스가 자주 변경될 경우 이 상황에서는 새로운 쿼리 계획이 필요하기 때문에 Prepared 스테이트먼트가 실패할 수 있습니다.

혼동하지 마세요.기억만 하면 됩니다.

  1. 문은 DDL과 같은 정적 쿼리에 사용됩니다. 즉, create, drop, alter 및 prepareStatement는 동적 쿼리에 사용됩니다.DML 쿼리
  2. prepareStatement 쿼리가 미리 컴파일되어 있는 동안 문의 사전 컴파일은 이루어지지 않습니다.이 때문에 prepareStatement는 시간이 효율적이기 때문입니다.
  3. prepareStatement는 작성 시 인수를 사용하는 반면 Statement는 인수를 사용하지 않습니다.예를 들어 테이블을 만들고 요소를 삽입하는 경우 :: prepareStatement를 사용하여 Statement 및 Insert 요소(dynamic)를 사용하여 테이블(static)을 작성합니다.

이 질문의 모든 답변에 따라 작동 중인 레거시 코드를 변경했습니다.Statement(단, SQL Injection을 사용하는 경우)를 사용하여 솔루션을 구축합니다.PreparedStatement주위의 의미론에 대한 이해가 부족하기 때문에 훨씬 느린 코드로Statement.addBatch(String sql)&PreparedStatement.addBatch().

그래서 다른 사람들이 같은 실수를 하지 않도록 제 시나리오를 여기에 나열해 두었습니다.

저의 시나리오는

Statement statement = connection.createStatement();

for (Object object : objectList) {
    //Create a query which would be different for each object 
    // Add this query to statement for batch using - statement.addBatch(query);
}
statement.executeBatch();

위의 코드에서는 수천 개의 다른 쿼리를 모두 같은 스테이트먼트에 추가했습니다.캐시되지 않은 스테이트먼트는 양호하고 이 코드는 앱에서 거의 실행되지 않기 때문에 이 코드가 더 빨리 동작했습니다.

SQL Injections를 수정하기 위해 이 코드를 로 변경했습니다.

List<PreparedStatement> pStatements = new ArrayList<>();    
for (Object object : objectList) {
    //Create a query which would be different for each object 
    PreparedStatement pStatement =connection.prepareStatement(query);
    // This query can't be added to batch because its a different query so I used list. 
    //Set parameter to pStatement using object 
    pStatements.add(pStatement);
}// Object loop
// In place of statement.executeBatch(); , I had to loop around the list & execute each update separately          
for (PreparedStatement ps : pStatements) {
    ps.executeUpdate();
}

그래서 저는 수천개의 데이터를 만들기 시작했습니다.PreparedStatement오브젝트 및 최종적으로는 배치 기능을 이용할 수 없습니다.시나리오에서는 수천 개의 UPDATE 또는 INSERT 쿼리가 존재하며 이들 쿼리는 모두 다릅니다.

성능 저하 없이 SQL 주입을 수정하는 것은 필수 사항으로, 이 방법으로는 불가능하다고 생각합니다.PreparedStatement를 참조해 주세요.

또한 삽입 배치 기능을 사용하는 경우 하나의 스테이트먼트만 닫는 것에 대해 걱정해야 하지만 이 리스트 접근법에서는 재사용 전에 스테이트먼트를 닫아야 합니다.Reusing a Prepared Statement

언급URL : https://stackoverflow.com/questions/3271249/difference-between-statement-and-preparedstatement

반응형