1) 쿼리의 실행과정
쿼리의 실행과정은 위 그림과 같다.
1) Parsing & Normalization Phase
- Query 문법 확인, Semantic check(?) 및 쿼리에 있는 테이블, 컬럼 존재여부 확인
2) Compilation Phase
- 쿼리를 machine이 이해할 수 있는 형식으로 컴파일
3) Query Optimization Phase
- 쿼리를 실행할 수 있는 방법들을 체크하고, 최적의 쿼리 실행 방법을 선택
4) Cache
- 3) 단계의 최적의 방법을 저장
5) Execution Phase
- 쿼리 실행
2) Statement, PreparedStatement의 동작 방식의 차이점
1️⃣ 캐시 사용 유무
// [Statement]
Connection conn = DriverManager.getConnection(url, id, pwd);
Statement stmt = conn.createStatement();
stmt.executeUpdate("Update Member Set Name = " + "JK" Where id = " + 100);
stmt.executeUpdate("Update Member Set Name = " + "SY" Where id = " + 101;
// [PreparedStatement]
Connection conn = DriverManager.getConnection(url, id, pwd);
String sql = "Update Member Set Name = ? Where id = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "JK");
pstmt.setInt(2, 100);
pstmt.executeUpdate();
pstmt.setString(1, "SY");
pstmt.setInt(2, 101);
pstmt.executeUpdate();
- Statement, PreparedStatement 방식 둘 다 Query를 컴파일하고 최적화한 다음 실행되기 전에 Caching 되지만 Statement는 첫 수행한 Query와 완전히 일치하는 Query를 요청하는 경우에만 캐싱한 데이터를 재활용할 수 있다.
- Statement의 경우, 첫 번째 Query와 일치하지 않는 별도의 Query를 실행하게 되면 컴파일을 다시 해야 한다.
즉, 위 그림의 1 ~ 5단계를 모두 다시 거쳐야 하는 셈이다.
- PreparedStatement 방식은 Statement 방식과 다르게 파라미터를 바인딩하기 때문에 기존에 컴파일된 Query를 재활용할 수 있다.
즉, 처음 1 ~ 5단계를 모두 거쳤으면 다음부터는 1 ~ 4단계는 뛰어넘고 바로 쿼리 실행이 가능하다.
- 또, 파라미터를 Query문 안에 직접 넣어주는 Statement 방식은 가독성도 좋지 않고 코딩하기에도 번거롭다.
2️⃣ SQL Injection 방지
// [기존 Statement 방식]
Connection conn = DriverManager.getConnection(url, id, pwd);
Statement stmt = conn.createStatement();
stmt.executeQuery("Select * from Member Where id = " + id + " and pwd = " + pwd);
→ 로그인 시, 사용자에게서 입력받은 값을 Where 조건절에 넣어주어 조회하는 Query이지만 만약, 다음과 같이 공격자가 파라미터 값을 악의적으로 조작해서 보낼 수도 있다.
// [사용자에게서 입력받은 값]
id = test123
pwd = 1234’ or 1=1
Query = Select * from Member Where id = ‘test123’ and pwd = ‘1234’ OR ‘1’ = ‘1’;
→ 이처럼 공격자가 악의적으로 파라미터 값을 조작하여 “OR 1=1” 조건을 추가하는 방법으로 사용자 정보를 탈취할 수 있다.
// [PreparedStatment 방식]
Connection conn = DriverManager.getConnection(url, id, pwd);
String sql = "Select * from Member Where id = ? and pwd = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, id);
pstmt.setString(2, pwd);
pstmt.executeQuery();
→ PreparedStatment 방식은 사용자에게서 받은 파라미터 값이 악의적으로 조작되었다 하더라도 파라미터 바인딩을 통해 SQL Injection을 방지할 수 있다.
→ 정확히는 pstmt.setString() 메소드 내부에서 사용되는 javaEncode() 메소드가 SQL Injection을 방지해주는데 내부 구현이 어떻게 되어있는지 살펴보자!
// [javaEncode() 메소드]
public static void javaEncode(String s, StringBuilder buff, boolean forSQL) {
int length = s.length();
for (int i = 0, i < length; i++) {
char c = s.charAt(i);
switch (c) {
case ‘\t’:
buff.append(“\\t”);
break;
case ‘\n’:
buff.append(“\\n”);
break;
case ‘\f’:
buff.append(“\\f”);
break;
case ‘“’;
buff.append(‘\’’);
break;
...
}
}
}
→ 이처럼 공격자가 악의적으로 조작한 파라미터 값에 “\”를 붙여줌으로써 SQL Injection을 방지할 수 있는 것이다.
---
출처 : [Why Prepared Statement is faster than Statement in Java JDBC](https://javabypatel.blogspot.com/2017/06/why-prepared-statement-is-faster-than-statement-in-java.html)
[Statement 보다 PreparedStatement를 사용해야 하는 이유](https://shuu.tistory.com/129)
'DB & SQL' 카테고리의 다른 글
[SQL] 서브쿼리란? 서브쿼리 종류 - 스칼라, 인라인 뷰, 중첩 (1) | 2024.05.19 |
---|---|
[DB] MySQL testdb 생성 (0) | 2024.05.18 |
[DB] 터미널 명령어를 이용한 기본적인 MySQL 사용방법과 zsh 환경변수 설정 - macOS (2) | 2024.05.18 |
[DB] MySQL 설치와 DB 생성, 연결 과정 - macOS (0) | 2024.05.18 |
DB connection 에서 URL이 의미하는 것 (0) | 2024.01.10 |
댓글