→ 이 둘의 가장 큰 차이는 캐시사용 여부의 차이이다.
쿼리문을 실행하게 될 때 [문장분석 → 컴파일 → 실행단계] 의 과정을 실행하게 되는데 Statement 의 경우 쿼리가 매번 실행될 때 이러한 과정이 일어나는 반면, PreparedStatement 의 경우 처음만 위 과정을 거친 후에 캐싱된 실행계획을 재사용하므로 DB 부하를 줄일 수 있다.
PreparedStatement
- 미리 컴파일 한 후 파라미터 값만 동적쿼리로 재사용할 때 주로 사용된다.
- 개발자 의도에 작성된 쿼리문이 캐싱되어 있으므로 SQL Injection 과 같이 임의적인 SQL문을 주입하여 실행되게 하는 보안상의 이슈도 막을 수 있다.
Statemetn
- 단 한번의 조회나 create, alter, drop 같은 작업을 할 시에는 Statement 를 사용하는데, 이 때 sql injection 이슈를 막기 위해 변수값에 대한 유효성 검사를 하는것이 필수이다.
[참고]
sql 인젝션의 경우에는 ;(세미콜론) 을 먼저 입력해주어 이전 쿼리문들은 모두 취소시킨 후에 내가 원하는 쿼리를 보내는 입력하는 것이 가장 일반적인 공격방법이다.
(1 ~ 입력받은 수) 를 Statement 방식과 PreparedStatement 방식으로 INSERT
public ResultParam callStatementAndPreparedStatement (Param param) {
// pool, 타임아웃별 종류 찾아보고 표로 정리해보자.
String url = "jdbc:mysql://localhost:3306/dev_study?characterEncoding=UTF-8&serverTimezone=UTC&socketTimeout=500";
Connection conn = null;
PreparedStatement pstmt = null;
Statement stmt = null;
ResultParam result = new ResultParam();
try {
conn = DriverManager.getConnection ( url, "root", "123123" );
// Statement
stmt = conn.createStatement();
String query = "";
long start = System.currentTimeMillis();
for (int i = 0; i < param.getNumber(); i++) {
query = "Insert Into testTable (num) Values(" + i + ")";
stmt.executeUpdate(query);
}
long end = System.currentTimeMillis();
result.setStatementResultTime(String.valueOf((end-start)/1000.0));
// PreparedStatement
String preQuery = "Insert Into testTable (num) Values(?)";
pstmt = conn.prepareStatement (preQuery);
start = System.currentTimeMillis();
for (int i = 0; i < param.getNumber(); i++) {
pstmt.setInt( 1, i);
pstmt.executeUpdate ();
}
end = System.currentTimeMillis();
result.setPreparedStatementResultTime(String.valueOf((end-start)/1000.0));
} catch(Exception e){
System.out.println (e.getMessage () );
} finally{
try {
pstmt.close ();
} catch (Exception ignored) {
}
try {
conn.close ();
} catch (Exception ignored) {
}
}
return result;
}
[RESULT]
* 1~10 인경우
{statementResultTime: "0.016", preparedStatementResultTime: "0.006"}
* 1~100 인 경우
{statementResultTime: "0.104", preparedStatementResultTime: "0.074"}
* 1~1000 인 경우
{statementResultTime: "0.016", preparedStatementResultTime: "0.006"}
* 1~10000 인 경우
{statementResultTime: "5.727", preparedStatementResultTime: "5.173"}