본문 바로가기

Programming/JSP

jsp : prepared statement와 statement의 차이점.


오라클은 내부적으로 라이브러리 캐쉬를 가지고 있습니다.
그리고 이 라이브러리 캐쉬내에는 실행된 SQL문장과 실행계획이 저장되어 있습니다.
사용자가 SQL을 실행할때마다 오라클은 이 SQL이 라이브러리 캐쉬에 있는 SQL과 동일한지
비교하고 만약 같다면 이미 기존에 있는 라이브러리 캐쉬의 실행계획을 가지고 SQL을 수행합니다.

이때 비교하는 규칙은 간단합니다. '모든 문자가 동일한가?'
하나의 오차도 없이(대소문자, 공백문자 모두 포함) 동일한지를 따지는 것입니다.

일반적인 SQL문장에서
SELECT * FROM EMP WHERE EMPNO = 1234;    와
SELECT * FROM EMP WHERE EMPNO = 2345; 는 다르게 파싱됩니다. 다른 문장으로 인식되기 때문입니다.

그러나 만약 비교할 값이 bind variable에 넣고
SELECT * FROM EMP WHERE EMPNO =: target_no;

이렇게 해주고 target_no를 변경하면서 실행되는 SQL문장은 모두 같은 SQL문장으로 인식됩니다.

PreparedStatement란 이처럼 bind variable의 사용을 가능케 하기 위하여 사용됩니다.
따라서 동일한 문장이(위처럼 값만 바뀐다거나 할 경우) 여러번 연속적으로 실행되거나
비교적 연속적으로(라이브러리 캐쉬에 있는 실행계획이 url에 의해 메모리에서 삭제되기 직전에 다시 실행되기만 한다면)
 실행된다면 월등한 성능향상을 얻을 수 있습니다.

 출처 : http://www.okjsp.pe.kr/seq/11057


추가 : 2011. 04 .01 : preparedstatement를 활용한 sql injection 1차방어(?)
statement를 사용하는 것보다 preparedstatement를 사용하는 것이 sql injection 공격을 방어하는데 도움이 됩니다.
위 SQL문에서 EMPNO 컬럼은 해당 테이블에서 정수값을 가진다고 셋팅이 되어있을 때를 가정해보겠습니다.
웹사이트 VIEW단에서 CONTROL단을 거쳐 MODEL로직까지 넘어가는 과정에서
URL을 임의로 지정하여 SQL query문을 조작하는 것을 injection이라고 하는데
statement 를 사용할 경우 보통 쿼리문작성을 위해 jdbc를 사용할 때
String query = "SELECT * FROM EMP WHERE EMPNO = " + empno;
이렇게 작성을 많이 합니다. 이러한 경우에는 request를 편의있게 활용하기 위해 보통 String으로 입력받아
바로 활용하는 경우가 많기 때문에 empno는 string문장이 되고 이는 URL을 이용하여 임의적인 data입력이 가능해집니다.
하지만 preparedStatement 클래스의 경우에는 사용방법이
String query = "SELECT * FROM EMP WHERE EMPNO = ?"; 
...
ps.setInt(1, empno); 이런식으로 사용이 됩니다.
따라서 강제적인 정수입력만이 요구되기때문에 임의적인 qeury문장을 통한 해킹에
1차적인(?) 방어는 가능한 것이죠.
위험한 예를 들어보겠습니다. statement의 경우에
DELETE FROM EMP WHERE EMPNO = "20 or 1=1" 라는 쿼리문 실행이 가능해집니다.

출처 : http://kr.forums.oracle.com/forums/thread.jspa?messageID=1449401