PreparedStatement와 CallableStatement의 차이

PreparedStatement

  • PreparedStatement는 Statement를 확장한다.
  • prepared: 준비된 → 준비된 컴파일. 미리 컴파일되어 준비하고 있기 때문에 statement에 비해 성능이 좋다.
  • 주로 매개변수 전달이 필요한 SQL 작성이나, FOR LOOP 등으로 여러 번 SQL을 실행하는 경우에 사용한다.
String sql = "UPDATE java_member SET name=?, tel=?, pw=? WHERE id=?";
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setString(1, name);
pstmt.setString(2, tel);
pstmt.setString(3, pw);
pstmt.setString(4, id);
int re = pstmt.executeUpdate();

 

 

CallableStatement

  • CallableStatement는 미리 작성해둔 프로시저를 실행하는 데 사용한다.
  • CallableStatement는 PreparedStatement를 확장한다.
  • ? 매개변수 자리에 프로시저에서 사용하는 매개변수와 가져올 값에 대한 세팅을 동시에 한다.
  • 프로시저 실행에 필요한 매개변수는 setString, setInt 등으로 지정하고, 프로시저 응답으로 받을 값들에 대한 데이터 타입을 registerOutParameter로 모두 지정해야 한다.
  • CallableStatement도 미리 컴파일되어 DB에 저장되어 있기 때문에 성능상으로 이점이 있다.
String sql = "{call bbs_find(?,?)}";
CallableStatement cs = con.prepareCall(sql);
cs.registerOutParameter(1, oracle.jdbc.OracleTypes.CURSOR);
cs.setString(2, writer);
cs.execute();
ResultSet rs = (ResultSet)cs.getObject(1);

 


CallableStatement

형식 및 구조

- 매개변수가 없는 저장 프로시저 호출
{call 프로시저명}
- IN 매개변수를 리턴하는 프로시저 호출
{call 프로시저명(?, ?, ...) }

 

CallableStatement 객체 생성

  • CallableStatement 객체는 Connection의 prepareCall() 메서드에 의해 생성된다.
  • 프로시저를 호출하는 query를 작성해서 prepareCall() 메서드의 인자값으로 넣어주면 된다.
    CallableStatement cstmt = con.prepareCall("{call bbs_add(?, ?, ?)}");

 


예제1

bbs에 게시글을 등록하는 프로시저를 작성하고 JDBC를 통해서 해당 프로시저를 호출해보자.

 

[오라클 프로시저]

--bbs에 게시글을 등록하는 프로시저
CREATE OR REPLACE PROCEDURE bbs_add(
    ptitle IN BBS.TITLE%TYPE,
    pwriter IN BBS.WRITER%TYPE,
    pcontent IN BBS.CONTENT%TYPE
)
IS
BEGIN
    INSERT INTO BBS(no, title, writer, content, wdate)
    VALUES(bbs_seq.NEXTVAL, ptitle, pwriter, pcontent, SYSDATE);
    COMMIT;
END;
/

 

[자바]

public class CallableStatementTest {

	public static void main(String[] args) throws Exception{
		Scanner sc = new Scanner(System.in);
		
		System.out.println("Title: ");
		String title = sc.nextLine();
		
		System.out.println("Writer: ");
		String writer = sc.nextLine();
		
		System.out.println("Content: ");
		String content = sc.nextLine();
		System.out.println(title+"/"+writer+"/"+content);
		
		//1. driver 로딩, db연동
		Connection con = DBUtil.getCon();
		//2. 프로시저를 호출하는 문장 작성
		String sql = "{call bbs_add(?, ?, ?)}"; //ptitle, pwriter, pcontent
		//3. CallableStatement 객체 얻기
		CallableStatement cstmt = con.prepareCall(sql);
		//4. CallableStatement의 set 메서드를 사용하여 ?를 대체할 값 지정
		//앞의 숫자는 ?의 순서이다.
		cstmt.setString(1, title);
		cstmt.setString(2, writer);
		cstmt.setString(3, content);
		//5. execute 쿼리 실행
		cstmt.execute();
		//6. db자원 반납
		cstmt.close();
		con.close();
		System.out.println("게시글 등록 완료!!");
	}

}

Scanner에 입력 및 실행 결과

SELECT * FROM bbs ORDER BY no DESC;

38번에 글이 등록되었다.

 


예제2

  • bbs에 저장된 내용들을 자바에서 출력하는 프로시저를 만들자. 
  • sys_refcursor를 이용하여 OUT 파라미터로 자바에 넘기면 자바에서 ResultSet으로 받을 수 있다.

[오라클 프로시저]

CREATE OR REPLACE PROCEDURE bbs_list(mycr OUT sys_refcursor) --OUT: 결과로 나갈 데이터
IS
BEGIN
    OPEN mycr FOR
    SELECT no, title, writer, content, wdate FROM bbs
    ORDER BY no DESC;
END;
/

 

[자바]

public class CallableStatementTest2 {

	public static void main(String[] args) throws Exception{
		//1. 프로시저를 호출하는 문장 작성
		String sql = "{call bbs_list(?)}";
		//2. driver 로딩, db연동 //3. CallableStatement 객체 얻기
		try(Connection con = DBUtil.getCon(); CallableStatement cs=con.prepareCall(sql);){
			//try() 괄호에 문장을 입력하면, 그 값들은 close가 자동으로 되므로, 따로 close를 하지 않아도 된다.
			//con.close()와 cs.close() 생략
			
			//4. CallableStatement의 registerOutParameter 메서드를 사용하여
			//CREATE PROCEDURE문에 OUT으로 정의된 ? (아웃 파라미터)의 데이터 유형을 등록
			cs.registerOutParameter(1, oracle.jdbc.OracleTypes.CURSOR);
			//5. excute 쿼리 실행
			cs.execute();
			//6. ResultSet 객체 얻어오기
			ResultSet rs = (ResultSet)cs.getObject(1); //cs 실행 결과를 Object로 받아 downcast
			//7. ResultSet 객체 순회
			while(rs.next()) {
				int no=rs.getInt("no");
				String title = rs.getString("title");
				String writer = rs.getString("writer");
				String content = rs.getString("content");
				Date wdate = rs.getDate("wdate");
				System.out.printf("%d\t%s\t%s\t%s\t%s\n", no,title,writer,wdate.toString(), content);
			}
			//8. 자원 반납
			rs.close();
		}catch(SQLException e) {
			e.printStackTrace();
		}
		
	}

}

실행 결과


예제3

bbs 게시글의 작성자 중 일부 문자가 포함된 작성자를 검색하는 프로시저를 만들어서 자바에서 검색이 가능하도록 만들어보자.

 

[오라클 프로시저]

CREATE OR REPLACE PROCEDURE bbs_find(
    mycr OUT sys_refcursor,
    pwriter IN BBS.WRITER%TYPE
)
IS
BEGIN
    OPEN mycr FOR
    SELECT no, title, writer, content, wdate FROM bbs
    WHERE writer LIKE '%'||pwriter||'%'
    ORDER BY no DESC;
END;
/

 

[자바]

public class CallableStatementTest3 {

	public static void main(String[] args) throws Exception{
		Scanner sc = new Scanner(System.in);
		System.out.println("검색할 작성자: ");
		String writer = sc.nextLine();
		//1. driver로딩, db연동
		Connection con = DBUtil.getCon();
		//2. 프로시저를 호출하는 문장 작성
		String sql = "{call bbs_find(?,?)}"; //mycr, pwriter
		//3. CallableStatement 객체 얻기
		CallableStatement cs = con.prepareCall(sql);
		//4. CallableStatement의 registerOutParameter 메서드를 사용하여
		//CREATE PROCEDURE문에 OUT으로 정의된 ?(아웃 파라미터)의 데이터 유형 등록
		cs.registerOutParameter(1, oracle.jdbc.OracleTypes.CURSOR);
		//5. CallableStatement의 set 메서드를 사용하여 ?를 대체할 값 지정
		cs.setString(2, writer);
		//6. execute 쿼리 실행
		cs.execute();
		//7. ResultSet 객체 얻어오기
		ResultSet rs = (ResultSet)cs.getObject(1); //첫 번째 물음표(커서)
		//8. ResultSet 객체 순회(커서 순회)
		while(rs.next()) {
			int no=rs.getInt("no");
			String title = rs.getString("title");
			String writer2 = rs.getString("writer");
			String content = rs.getString("content");
			Date wdate = rs.getDate("wdate");
			System.out.printf("%d\t%s\t%s\t%s\t%s\n", no,title,writer2,wdate.toString(), content);
		}
		//9. db자원 반납
		rs.close();
		cs.close();
		con.close();
	}

}

'kim'이 들어간 작성자 - kim, kimcheol이 쓴 게시글을 보여준다.

 

+ Recent posts