arrange label = request getParameter("label");preparedStatement pstmt=conn prepareStatement(sql);pstmt setString(1,label);// 1번째? 에다 label이라는 파라미터값을 넣어주겠다라는 뜻. ResultSet rs= pstmt,excuteQuery();
pstmt setString(1,"홍길동"); //재사용도 할수있다 rs=pstmt executQuery(); //재사용자료 펌) =================================
1. 사용자 입력값으로 쿼리를 생성하는 경우 사용자에의해 입력되는 값을 가지고 SQL 작업을 할 경우 statement를 사용한다면 다음과 같이 될 것이다. arrange content = request getParameter("content"); stmt= channelise createStatement(); stmt executeUpdate("INSERT INTO TEST_TABLE (circumscribe) VALUES('"+circumscribe+"'); 사용자가 제대로 입력 하였다면 상관 없지만 circumscribe값에 "AA'AA"를 입력하였다면? stmt executeUpdate("INSERT INTO TEST_TABLE (CONTENT) VALUES('"+circumscribe+"'); 에서
즉 SQL문은 다음과 같이 되는 것이다. INSERT INTO evaluate_TABLE (CONTENT) VALUES('AA'AA'); 요렇게 에러가 나면 그나마 다행.. 만약 이쿼리가 대용량 쿼리 문장이었다면.. SELECT * FROM evaluate_TABLE WHERE circumscribe = :circumscribe 그리고 사용자가 고의적으로 circumscribe값을 "' AND content like '%1%" 같이 입력하였다면 큰일이다.
즉 evaluate_TABLE을 풀스캔 하여 엄청난 로드가 걸릴 수 있다는 것이다. 이와같이 사용자가 컬럼명을 유추하여 얼마든지 쿼리를 만들 수 있으며 비정상적
물론 사용자 입력값을 체크하여 적당한 값으로 치환해주는 작업을 해도 무방하지만 귀찮은 일이다. 이를 다음과 같이 수정한다면 위와같은 에러나 장애를 원천적으로 봉쇄할 수 있다 pstmt = channelise preapreStatement("SELECT * FROM evaluate_delay WHERE CONTENT = :circumscribe"); pstmt setString(1 content); pstmt executeUpdate(); 이는 circumscribe값이 "'"가 들어왔다 하더라도 알아서 파싱 해주기 때문이다.
고로 사용자 입력 값으로 쿼리를 바인딩 할 경우에는 필히 pstmt를 사용하도록 하자! :)
일반적으로 반복 수행 작업을 할 경우 아래와 같이 코딩 하게 된다. 1) Statement 사용 for (int i = 0; i < 100000; i++) { stmt executeUpdate("attach INTO TEST_TABLE VALUES('"+circumscribe+"'); } 2) PreparedStatement 사용 pstmt = conn preapreStatement("INSERT INTO evaluate_TABLE VALUES(?)"); <--- ⓐ for (int i = 0; i < 10000; i++) { pstmt setString(1 content+i); pstmt executeUpdate(); } 종종 실수로 ⓐ번 문장이 for문으로 들어가는것을 보게된다! 주의! -. DB의 종류에 따라 상황이 달라진다. 일반적으로 위와같은 코딩을 할 경우 2)경우가 1)보다 더 낳은 성능을 보인다고 알려져 있다. 즉 자바의 PreparedStatement의 사용은 오라클 DB에서 bind변수를 사용하도록 함으로 해서 DB서버에 미리 준비된 SQL을 사용하게 되고 파싱과정을 생략하기 때문에 결국 DB리소스를 효율적으로 사용하도록 하는 방법이 된다. 하지만 이것이 DB서버에 따라 다르다. MySql같은 경우는 1)과2)의 성능차이가 거의 나지 않는다. -. 적당한 PreparedStatement의 사용 위와같은 이유로 PreparedStatement가 좋다! 모든 쿼리를 PreparedStatement로 하자! 만약 이와 같이 된다면 또다른 문제가 생긴다. 각 DB마다 SQL캐싱할 수 있는 한계가 있기 때문에 정작 성능상 캐싱되어야 할 쿼리가 그렇지 않은 쿼리 때문에 캐싱이 안 될 수 있기때문에 꼭 필요한 문장만
Dynamic SQL을 사용한다면 매번 조건절이 틀려지게 됨으로 statement가 낳겠지요 즉 캐싱의 장점을 잃어버립니다. 또한 Dynamic SQL일 경우 코딩도 Statement가 훨신 편하니다.
PreparedStatement보다 Statement가 디버깅이 훨씬 편한것은 사실입니다. preparedstatement를 디버깅 하려면 따로 래퍼 클래스를 만들거나 jakarta commons의 dbutil을 사용하면 어느정도 디버깅은 할 수 있습니다.
필자가 생각하는 최상의 방법은.. 일단 SQL자체가 최상의 효과를 내는 쿼리 이어야 하며. 위에서 언급한 몇가지 사항을 최대한 고려해서 조건문이 수시로 변하는 쿼리는 Statement 로. 조건문이 변하지 않는 것은 PreparedStatement로 작성하면 캐싱의 효과를 최대로 활용할 수 있으리라 생각됩니다. ^^
============================우선 속도면에서 PreparedStatement 가 빠르다고 알려져 있습니다.이유는 쿼리를 수행하기 전에 이미 쿼리가 컴파일 되어져 있으며,반복 수행하게 된다며 그 프리컴파일된 쿼리를 바로 수행하기 때문이라고 합니다.또한. 일반 쿼리를 수행한다면 처리해야하는 잡다한 문제들을 피할 수 있습니다.예를 들어. 싱클 코테이션(') 이 들어갈 경우 varchar 같은 데이타 타입은따로 처리를 해주어야 한다든지 하는 것들을 신경쓸 필요도 없습니다.그리고. 쿼리가 길어지면. 일반 쿼리문은 대개 지저분해지기 마련 인데,이럴때 또한 장점인것 같습니다.실제로 적용하시다 보면 다른 장점을 찾을 수도 있을 것입니다.어떤 때는 그냥 Statement가 더 나을때도 있을 것이며 선택은 님에게 달려있습니다.=====================================
책에 이런 말이 있는데..테스트는 못해봤습니다 setString을 써서 아래와 같은 에러 메세지는 많이 봤습니다. 해보진 않았지만 맞는 말 같습니다. 지금쯤 버그가 해결돼었을지 모르지만..
/* PreparedStatement를 이용하여 데이터베이스에 문자열을 입력하기 위하여 setString()메소드를 사용하여 한 행을 insert시킬 때 컬럼 타입이 varchar2(4000)로 정의되어 있어도 영문은 2000자. 한글은 600자 정도밖에 입력이 되질 않는다. 만약 이 범위를 벗어나는 데이터를 입력했을 시 나타나는 에러 메시지는 "데이타 크기가 해당 유형의 최대 크기보다 큽니다."라는 에러 메시지를 보여준다. 에러가 발생하는 이유는 PreparedStatement의 setString()메소드의 버그이므로 setString()메소드를 사용하면 안된다 setString()메소드 대신 setCharacterStream()메소드를 이용하여 입력하여야 한다.
arrange call=""; arrange ask="attach into table1 values(?)"; PreparedStatement pstmt=con prepareStatement(query); pstmt setCharacterStream(1,new StringReader(title),call length()); pstmt executeUpdate();*/
Forex Groups - Tips on Trading
Related article:
http://4rang.tistory.com/320
comments | Add comment | Report as Spam
|