※Statement PreparedStatement의 차이점과 PreparedStatement를 사용할 때의 장점

 

java.sql.Statement Connection에서 태어난다.

코드로 말하자면, 다음과 같은 형식이다.

java.sql.Statement = java.sql.Connection.createStatement();

 

java.sql.Statement를 상속한 것이

java.sql.PreparedStatement이고,

이것을 또 상속한 것이 java.sql.CallableStatement이다.

 

상속했다 함은 이전의 메소드를 모두 사용할 수 있으며,

새로 추가된 기능을 수행하는 메소드를 갖고 있다는 뜻이다.

 

Statement에서는 executeQuery(), executeUpdate() 메소드를 실행하면서

파라미터로 SQL문을 전달한다.

PreparedStatment는 커넥션에서 생성하면서 SQL문을 먼저 보낸다.

이렇게 준비를 시켜놓은 다음에 setXXX() 메소드를 통해서 값을 정해주고,

executeQuery(), executeUpdate()를 실행하게 된다.

 

다음 예제는 15000건의 데이터를 Statement를 통해서 입력하는 소스이다.

[예제 7-1]           jdbc07.jsp

<%@ page import="java.sql.Connection,

                 java.sql.Statement,

생략

Statement stmt = null;

StringBuffer queryBuf = new StringBuffer();

try {

    // Connection을 가져온다.

    conn = DsConn.getConnection();

    // 테이블을 생성하는 쿼리

    queryBuf.append("CREATE TABLE TEST_TABLE ( ")

        .append(" SEQ NUMBER NOT NULL, ")

        .append(" SUBJECT VARCHAR(200) NOT NULL")

        .append(" ) ");

생략

    // Statement를 생성한다.

    stmt = conn.createStatement();

%>start:<%=System.currentTimeMillis()-sTime%><hr><%

    // 반복 15000

    for(int i=0; i<15000; i++) {

    //   쿼리를 만들어서 실행한다.

        queryBuf.setLength(0);

        queryBuf.append("INSERT INTO TEST_TABLE (SEQ, SUBJECT) VALUES ( " )

                .append(i).append(", '이 행은 ")

                .append(i).append(" 번째 입력되었습니다.' ) ");

        stmt.executeUpdate(queryBuf.toString());

    } // end for

이하 생략

 

쿼리(query; sql)를 만들 때, 문자열을 +로 더해주지 않고 StringBuffer를 이용해서 만든 이유는 작지만 무시할 수 없는 성능에 대한 배려이다. String 덧셈할 때 각 항마다 새로운 String 객체가 생성되어 StringBuffer로 더해지는 과정이 내부적으로 일어나기 때문에, 자원면에서, 속도면에서 차이가 나게 된다. 이것을 StringBuffer를 이용해서 구현하면, 생략되기 때문에 절약이 되는 것이다. 웹 어플리케이션같이 수많은 사람들이 동시에 접근하는 환경에서 작은 차이가 큰 결과를 가져오게 되므로 주의해야 한다.

이렇게 문자열을 나눠서 쿼리를 만들 때 또 한 가지 주의할 점은 문자열 마지막이나 맨 처음에 공백을 두는 것이 필요하다.

Statement 인스턴스인 stmt는 한 번 사용한 후에 재사용이 가능하다. 대신 다른 쿼리를 수행하기 전에 close() 로 닫아주어야 한다.

 

 

다음은 PreparedStatement를 사용할 경우이다. 앞의 예제와 비교해보면 쉽게 차이점을 알 수 있다.

[예제 7-2]           jdbc08.jsp

<%@ page import="java.sql.Connection,

                 java.sql.PreparedStatement,

                 java.sql.SQLException,

생략

PreparedStatement pstmt = null;

생략

    // 데이터를 입력하는 쿼리

    queryBuf.setLength(0);

    queryBuf.append("INSERT INTO TEST_TABLE (SEQ, SUBJECT) VALUES ")

            .append("( :seq , '이 행은 '||:subject||' 번째 입력되었습니다.' )");

// mysql 등 다른 db에서는 별칭(:필드명)를 사용하는 대신 ? 로 대치한다.

//      .append("( ? , '이 행은 '||?||' 번째 입력되었습니다.' )");

 

    // 다시 PreparedStatement를 생성한다.

    pstmt = conn.prepareStatement(queryBuf.toString());

%>start:<%=System.currentTimeMillis()-sTime%><hr><%

    // 반복 15000

    for(int i=0; i<15000; i++) {

    //   쿼리를 실행한다.

        pstmt.setInt(1, i);

        pstmt.setInt(2, i);

        pstmt.executeUpdate();

    } // end for

이하 생략


import에서 가져오는 것은 java.sql.PreparedStatement 이다.

커넥션에서 사용하는 메소드는 createStatement() 대신 prepareStatment(String) 메소드이다.

주의할 점은 클래스명은 PreparedStatement 이고 메소드는 prepareStatement() 라는 것이다.

 

executeUpdate() 메소드에 파라미터로 쿼리를 보내 줄 필요가 없다. 데이터를 입력하는 오라클의 INSERT 쿼리문을 보면 실행할 때마다 가변적으로 생성하지 않고, 값이 들어갈 자리를 :필드명 의 형태인 바인드 변수로 만들어 놓았다. 코드의 가독성을 높이는 효과가 있다. 이것은 다른 DB에서는 일반적으로 ? 로 사용되어 왔기 때문이다.

 

SQL문에서 문자열은 '(작은따옴표)로 감싸지는데 문자열의 더하기는 ||를 사용해서 더해진다. 위 문장은 "이 행은 " + :subject + " 번째 입력되었습니다." 로 해석할 수 있다.

만일 '이 행은 :subject 번째 입력되었습니다.' 처럼 안에 집어넣을 경우 :subject 가 바인드 변수로 인식되지 않고 문장의 일부로 해석되기 때문에 실행 중에 다음과 같은 에러를 발생하게 된다. 다음 에러는 바인드 변수 갯수와 setXXX()의 갯수가 맞지 않을 때 일어난다.

java.sql.SQLException: ORA-01006: 바인드 변수가 없습니다

 

단지 바인드 변수에 지정된 값만 setInt(순서, int) 메소드로 넣어주면 된다.

자바코드에서 인덱스는 0부터 시작하지만 JDBC에서 사용한 순서는 1부터 시작된다.

setInt(1, i) 대신 setString(1, String.valueOf(i) ) 와 같이 String 형태의 사용도 가능하다.

DB 필드의 타입에 상관없이 모두 String으로 처리가 가능하다.

 

getXXX(), setXXX() 모두 getString(), setString()으로 해도 상관없다.

단지 차이점이라면 데이터 타입의 검사를 DB에서 하느냐 아니면 웹 어플리케이션에서 하느냐 정도일 것이다.

즉 타입에 맞지않는 값이 처리될 경우, 예외의 발생이 DB에서 SQLException으로 나오는가, 웹어플리케이션에서 예외를 발생시키는가에 대한 차이이다.

 

- 출처 : http://www.okjsp.pe.kr "kenu"님

 
2010/01/11 13:16 2010/01/11 13:16

트랙백 주소 :: http://thinkit.or.kr/programming/trackback/23

댓글을 달아 주세요