ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • PreparedStatement를 사용한 쿼리 실행 및 기타 여러가지
    Data Base 2007. 11. 26. 20:15

    java.sql.PreparedStatement는 java.sql.Statement와 동일한 기능을 제공한다.
    차이점이 있다면 SQL 쿼리의 틀을 미리 생성해 놓고 값을 나중에 지정한다는 것이다.

    - PreparedStatement를 사용하는 순서
    ① Connection.prepareStatement() 메소드를 사용하여 PreparedStatement 생성
    ② PreparedStatement의 set 메소드를 사용하여 필요한 값 지정
    ③ PreparedStatement의 executeQuery() 또는 excuteUpdate() 메소드를 사용하여 쿼리 실행
    ④ finally 블록을 사용한 PreparedStatement 를 닫는다.(close() 메소드 실행)

    PreparedStatement를 생성할 때에는 실행할 쿼리를 미리 입력하는데,
    이때 다음과 같이 값 부분을 물음표('?')로 대치한 쿼리를 사용한다.

    PreparedStatement pstmt = null;
    ...
    pstmt =
        conn.prepareStatement("insert into MEMBER (MEMBERID, NAME, EMAIL) values (?,?,?)");


    위와 같이 PrepagedStatement 객체를 생성한 다음에
    PreparedStatement가 제공하는 set 계열의 메소드를 사용하여
    물음표를 대체할 값을 지정해 주어야 한다.

    pstmt.setString(1,"aa"); //첫번째 물음표의 값 지정
    pstmt.setString(2,"bb"); //두번째 물음표의 값 지정

    이때 첫번째 물음표의 인덱스는 1이며,
    이후의 물음표의 인덱스는 나오는 순서대로 인덱스 값이 1씩 증가한다.

    ResultSet의 get 계열의 메소드와 마찬가지로 PreparedStatement는
    각각의 SQL 타입을 처리할 수 있는 set 계열의 메소드를 제공하고 있으며
    각 메소드는 다음과 같다.

    setString(int index , String x)
    - 지정한 인덱스의 파라미터 값을 x로 지정한다.

    setCharacterStream(int index , Reader reader , int length)
    - 지정한 인덱스의 파라미터 값을 LONG VARCHAR 타입의 값으로 지정할때 사용한다.
       Reader는 값을 읽어올 스트림이며, length는 지정한 문자의 길이를 나타낸다.

    setInt(int index , int y)
    - 지정한 인덱스의 파라미터 값을 int 값 x 로 지정한다.

    setLong(int index, long x)
    - 지정한 인덱스의 파라미터 값을 long 값 x 로 지정한다.

    setDouble(int index, double x)
    - 지정한 인덱스의 파라미터 값을 double값 x 로 지정한다.

    setFloat(int index,float x)
    - 지정한 인덱스의 파라미터 값을 float값 x로 지정한다.

    setTimestemp(int index,Timesetamp x)
    - 지정한 인덱스의 값을 SQL TIMESTMAP 파일을 나타내는 java.sql.Timestamp 타입으로 지정한다.

    setDate(int index,Date x)
    - 지정한 인덱스의 값을 SQL DATE 타입을 나타내는 java.sql.Date 타입으로 지정한다.

    setTime(int index, Time x)
    - 지정한 인덱스의 값을 SQL TIME 타입을 나타내는 java.sql.Time 타입으로 지정한다.


    PreparedStatement 에서 LONG VARCHAR 타입의 값을 지정하기

    PrepageStatement 에서 LONG VARCHAR 타입의 값을 지정할 때에는 다음의 메소드를 사용한다.

    ㆍsetCharacterStream(int index,Reader reader, int length)

    이 메소드를 사용해서 값을 지정할 때에는 다음과 같은 코드를 사용하면 된다.

    try{
        String value = "..."; //LONG VARCHAR에 넣을 값
        pstmt = conn.prepareStatement(...);
        java.io.StringReader reader = new java.io.StringReader(value);
        pstmt.setCharacterStream( 1, reader, value.length() );
        ....
    }catch(..) {
        ...
    } finally {
        ....
    }


    ResultSet에서 getCharacterStream() 메소드를 사용해서 LONG VARCHAR 값을 읽어 오는 것과 비교해서 코드가 간단해진 것을 알 수 있다.

    PreparedStatement 쿼리를 사용하는 이유

    Statement 쿼리를 사용해도 되는데 굳이 PreparedStatement 쿼리를 사용하는 이유

    - 반복해서 실행되는 동일 쿼리의 속도를 증가시키기 위해
    - 값 변환을 자동으로 하기 위해
    - 간결한 코드를 위해

    예를 들어

    select * from MEMBER where MEMBERID = 'abc';

    쿼리를 반복적으로 실행한다면

    stmt = conn.createStatement();
    stmt.executeQuery("selelct * from MEMBER where MEMBERID = '"+abc+"'");
    stmt.executeQuery("selelct * from MEMBER where MEMBERID = '"+def+"'");
    stmt.executeQuery("selelct * from MEMBER where MEMBERID = '"+ghi+"'");

    이와 같이 해야 한다.

    반면 PreparedStatement 클레스를 사용하면 다음과 같이 코드가 변경된다.
    Connection.prepareStatement() 메소드를 호출하면 DBMS는 미리 SQL 쿼리를 분석한다.
    PreparedStatement.executeQuery() 메소드를 실행할 때에는 곧바로 쿼리를 실행하게 된다.

    ①같은 형태의 쿼리에 대해서 분석을 반복해서 하지 않기때문에 쿼리 실행 속도가 빨라진다.

    pstmt = conn.prepareStatement("select * from MEMBER where MEMBERID = ?");
    pstmt.setString(1,"abc");
    pstmt.executeQuery();
    pstmt.setString(1,"def");
    pstmt.executeQuery();
    pstmt.setString(1,"ghi");
    pstmt.executeQuery();

    ② 두번째 장점은 값을 변경하지 않아도 된다는 점이다.
    Statement 를 사용해서 " 최'범균"과 같이 중간에 작은 따옴표가 포함된 값을 지정할 때에는
    다음과 같이 작은따옴표를 두번 사용하는 형태로 변경해 주어야 한다.

    stmt.executeQuery("select * from member where name = '"+"최범균'범균".replaceAll("'","'");

    하지만,PreparedStatement의 경우 setString() 메소드를 호출할 때 알아서 값을 변경해주기
    때문에 위 코드와 같이 작은 따옴표를 처리해 줄 필요가 없다.

    pstmt.setString(1,"최'범균");

    TIMESTAMP나 DATE,TIME 타입의 경우는 더욱 복잡해져서 DBMS마다 날짜 및 시간을 표현하는 방식이 다르기 때문에 위의 방식으로 할 경우 DBMS마다 코드가 달라진다.
    하지만, PreparedStatement를 사용하면 DBMS에 상관없이 다음과 같은 동일한 코드를 사용하게 된다.

    Timestamp time = new Timestamp(System.currentTimeMills());
    pstmt.setTimestamp(3,time);

    ③마지막으로 PreparedStatement 클레스를 사용하게 되면 코드가 깔끔하게 된다.
    Statement 클레스를 사용할 경우 UPDATE 쿼리는 다음과 같은 형태를 띄게 된다.

    stmt.executeQuery("update member set NAME = '"+name+"' where "+ "MEMBERID = '"+id+"'");

    지정할 값이 많아질 경우 따옴표가 복잡하게 얽히기 때문에 코딩상의 오류가 발생할 수 있고,
    나중에 코드를 수정할 때에도 조심스럽게 변경해야 한다.
    하지만 PreparedStatement 를 사용하면 위의 코드는
    다음과 같이 복잡하지 않은 코드로 변경된다.

    PreparedStatement pstmp = conn.prepareStatement(
                    "update member set NAME = ? where MEMBERID = ? ");
    pstmt.setString(1,name);
    pstmt.setString(2,id);

Designed by Tistory.