관리 메뉴

엉망진창

execute / executeQuery / executeUpdate 차이 본문

Study_Web/JSP

execute / executeQuery / executeUpdate 차이

엉망진창 2008. 1. 28. 18:05

4. Statement


4.1 개요

Statement 객체는 SQL문을 데이터베이스로 전송하는데 사용한다. 실제로 다음과 같은 세종류의 Statement 객체들이 있고 모두 주어진 접속상에서 SQL문들을 실행하기위한 컨테이너들로써 동작한다.

  • Statement
  • Statement로부터 상속받은 PreparedStatement
  • PreparedStatement로부터 상속받은 CallableStatement


이러한 것들은 특정 형태의 SQL문들을 전송하기위해 분화되어졌다.

Statement 객체는 매개변수 없는 간단한 SQL문을 실행하는데 사용되며, Statment 인터페이스에는 SQL문들을 실행하고 결과들을 검색하기 위한 기본적인 메쏘드들이 있다.

PreparedStatement 객체는 IN 매개변수를 가지거나 가지지 않는 프리컴파일된 SQL문을 실행하는데 사용되고, PreparedStatement 인터페이스는 IN 매개변수들을 다루기 위한 메쏘드들을 포함한다.

CallableStatement 객체는 데이터베이스 저장 프로시져(stored procedure)의 호출을 실행하는데 사용되며, CallableStatement 인터페이스에는 OUT 매개변수들을 다루기 위한 메쏘드들이 있다.

4.1.1 Statement 객체들을 생성하기

일단 특정 데이터베이스에 연결되면, 그 접속은 SQL문들을 전송하는데 사용된다. Statement 객체는 아래의 코드처럼 Connection의 createStatement 메쏘드로서 생성되어진다. :

 Connect con = DriveManager.getConnection(url, "sunny", ""); Statement stmt = con.createStatement(); 


데이터베이스로 전송되어질 SQL문은 Statement 객체를 실행하기위한 메쏘드들의 인자로써 공급되어진다.:

 ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table2); 


4.1.2 Statement 객체들을 수행하기

Statement 인터페이스는 SQL문들을 실행하기위한 세가지 다른 메쏘드들(executeQuery, executeUpdate, execute)을 제공한다.
사용하는 것은 SQL문이 무엇을 만드느냐에 좌우된다.

executeQuery 메쏘드는 하나의 result set을 만드는 SQL문들에서 사용된다.
명백하게 하기 위해서, 메쏘드의 실행이 리턴하는 것인 리턴값(return value)과 SQL문이 만드는 것인 결과(result)의 용어를 구별할 것이다.
예를들어, executeQuery 메쏘드는 ResultSet 객체를 리턴한다.
그것이 실행하는 SQL문은 result set을 만든다.
그래서 이경우에는 리턴값(SQL문에 의해 생성되어진 result set을 포함하는 ResultSet 객체)은 결과와 같다.

그러나 executeUpdate 메쏘드에서는 다르다.
이 메쏘드는 INSERT, UPDATE 또는 DELETE 문들, 그리고 또한 CREATE TABLE과 DROP TABLE과 같은 SQL DDL(Data Definition Languate)문들을 실행하는데 사용되어진다.
INSERT, UPDATE, DELETE 문의 결과는 테이블내의 0 이나 많은 열들내에서 하나이상의 행을 수정하는 것이다.
executeUpdate의 리턴값은 작용한 열의 개수(갱신 카운트로 간주되는)를 나타내는 정수이다.
이것은 update문의 결과와는 전적으로 다르다. CREATE TABLE과 같은 SQL문은 또다른 상황이 나타난다.
즉, 그것은 새로운 테이블을 만들고, 그것이 결과이지만, 아무것도 리턴하지는 않는다.
이러한 경우에 executeUpdate 메쏘드는 0를 리턴한다.
따라서 executeUpdate의 리턴값이 0 일 때, 그것은 다음 두가지 중 하나를 의미할 수 있다.

   1) 실행된 SQL문은 열들에 영향을 주지 않는 INSERT, UPDATE 또는 DELETE이다.
   2) 실행된 SQL문이 DDL 문들이다.

실행문을 위한 모든 메쏘드들은 하나가 오픈되어있다면 호출된 Statement 객체의 현재 result set을 닫아야 한다.
이것은 Statement 객체를 다시 실행하기전에 현재 ResultSet 객체의 어떠한 처리도 완결해야 할 필요가 있다는 것을 의미한다.

Statement 인터페이스에 있는 모든 메쏘드를 상속하는 PreparedStatement는 자체의 executeQuery, executeUpdate 그리고 execute 메쏘드를 가지고 있음을 주의해야한다.
Statement 객체들은 자체에 SQL문을 포함하지 않는다.
그러므로 Statement.execute 메쏘드의 인자로써 제공되어져야 할 것이다.
PreparedStatement 객체들은 이러한 메쏘드의 매개변수로써 SQL문을 제공하지 않는다.
왜냐하면 이미 사전에 컴파일된 SQL문을 포함하기 때문이다.
CallableStatement 객체들은 PreparedStatement 형태의 이러한 메쏘드들을 상속한다.
PreparedStatement 나 CallableStatement 버전의 이러한 메쏘드들에서 질의(query) 매개변수를 사용하는 것은 SQLException이 발생하도록 한다.

4.1.3 Execute 메쏘드 사용하기

execute 메쏘드는 SQL문이 여러개의 ResultSet 객체나 여러개의 갱신 카운트 또는 Result 객체들과 갱신 카운트들의 결합을 리턴하는 것이 가능할 때만 사용되어져야 한다.

이러한 결과들의 다중 가능성은 비록 드물지만, 어떠한 저장 프로시져를 실행하거나 알 수 없는 SQL 스트링(즉, 컴파일때에 어플리케이션 프로그래머가 알수 없는)을 동적으로 실행할 때 나타날 수 있다.
예를 들어, 사용자가 CallableStatement 객체(7장의 "CallableStatsment를 찹조)를 사용하여 저장 프로시져를 실행하고, 그런 저장된 프로시져가 갱신(update)하고, 그런다음 선택(select)하고, 그 다음에 갱신(update), 그런다음 다시 선택(select) 등을 수행할 수 있다.
전형적으로 저장 프로시져를 사용하는 사람은 무엇이 리턴되는지를 알 것이다.

execute 메쏘드는 평범하지 않은 경우들을 처리하기 때문에, 결과들을 검색하는 것이 몇가지의 특별한 처리를 요구한다는 것은 당연하다.
예를 들어, 프로시져가 두 개의 result set을 리턴한다고 알고 있다고 가정하자.
프로시져를 실행하기위해서 execute 메쏘드를 사용한 후에, 첫 번째 result set을 얻기위해서 getResultSet 메쏘드와 그것으로부터 값을 검색하기위해서 적당한 getXXX 메쏘드를 호출해야만 한다.
두 번째 result set을 얻기 위해서는, getMoreResults와 두 번째 getResultSet 메쏘드를 호출할 필요가 있다.
만약 프로시져가 갱신 카운트를 리턴한다면, getUpdateCount 메쏘드를 호출한다.

리턴되어질 것이 무엇인지 알지 못하는 경우에는 더욱 복잡해진다.
execute 메쏘드는 결과가 ResultSet 객체이면 true, 자바 int 이면 false를 리턴한다.
만약 int를 리턴하면, 이것은 결과가 갱신카운트이거나 실행된 SQL문이 DDL 명령이라는 것을 의미한다.
execute 메쏘드를 호출한 후에 해야할 첫 번째 일은 getResultSet 이나 getUpdateCount 중 하나를 호출하는 것이다.
getResultSet 메쏘드는 두 개이상의 ResultSet 객체들중 첫 번째인 것을 얻기위해서 호출되어진다.
그리고 getUpdateCount 메쏘드는 두 개이상의 갱신 카운트중 첫 번째인 것을 얻기 위해서 호출되어진다.

SQL문의 결과가 result set이 아닐 때, getResultSet 메쏘드는 null을 리턴할 것이다.
이것은 결과가 갱신 카운트이거나 더 이상의 결과들이 없음을 의미할 수 있다.
이러한 경우에서 null이 정말로 무엇을 의미하는지 알기위한 유일한 방법은 정수를 리턴하는 getUpdateCount 메쏘드를 호출하는 것이다.
이 정수는 결과가 result set인지 결과가 없는지를 가리키는 호출문에 의해 영향받는 열들의 번호나 -1이 될 것이다.
만약 getResultSet 메쏘드가 이미 null을 리턴했다면, 이것은 결과가 ResultSet 객체가 아님을 의미하고, 그러다음 -1의 리턴값은 더 이상의 결과가 없다는 것을 의미해야만 한다.
바꾸어 말하면, 다음이 true일 때는 (더 이상의) 결과가 없다:

 ((stmt.getResultSet() == null) && (stmt.getUpdateCount()) == -1) 


만약 getResultSet 메쏘드를 로드하고 그것이 리턴한 ResultSet객체를 처리한다면, 다른 result set 이나 갱신 카운트가 있는기 보기위해서 getMoreResults 메쏘드를 호출할 필요가 있다. getMoreResults가 true를 리턴한다면, 실제로 다음 result set을 검색하기위해서 getResultSet 메쏘드를 다시 호출할 필요가 있다. 이미 위에서 언급한것처럼, 만약 getResult이 null을 리턴한다면, null이 결과가 갱신카운트인 것을 의미하는지 또는 더 이상의 결과가 없다는 것을 의미하는를 알기위해서 getUpdateCount 메쏘드를 호출해야만 한다.

getMoreResults가 false를 리턴할 때, SQL문이 갱신 카운트를 리턴하거나 더 이상의 결과가 없다는 것을 의미한다. 그래서 경우를 발견하기 위해서 getUpdateCount 메쏘드를 호출할 필요가 있다. 이러한 상황에서, 다음이 true이면 더 이상의 결과는 없다.:

 ((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1)) 


아래에 있는 코드는 execute 메쏘드를 호출함으로 생성되는 모든 result set과 갱신 카운트를 접근하는 것을 확인할 수 있는 한가지 방법을 설명한다.:

 stmt.execute(queryStringWithUnknownResults); while (true) { int rowCount = stmt.getUpdateCount(); if (rowCount > 0) { // This is an update count System.out.println("Rows changed = " + count); stmt.getMoreResults(); continue; } if (rowCount = 0) { // DDL command or 0 updates System.out.println("No rows changed or statement was DDL command"); stmt.getMoreResults(); continue; } // if we have gotten this far, we have either a result set // or no more result. ResultSet rs = stmt.getResultSet; if (rs != null) { ... // use metadata to get info about result set columns while (rs.next()) { ... // process results stmt.getMoreResults(); continue; } break; // there are no more results } 


4.1.4 Statement 완성

접속이 auto-commit 모드에 있을 때, 그것내에서 실행되어지는 SQL문들은 그것들이 완결되어질 때 커미트(commit)되거나 롤백(rollback)된다. SQL문은 실행되어지고 그것의 결과가 리턴되어지며 완결로 간주될 것이다. 거의 모든 경우에서, 이것은 executeQuery 메쏘드나 executeUpdate 메쏘드를 호출할 때 발생한다. 그러나 execute 메쏘드가 호출되는 드문 경우에서, SQL문은 그것이 생성한는 result set이나 갱신 카운트가 검색되어질 때 까지 완결되지 않는다.

어떤 DBMS들은 저장 프로시져내의 각 SQL문을 개별적인 SQL문으로 처리하고 몇몇 DBMS들은 전체 프로시져를 하나의 복합 SQL문으로 처리한다. 이러한 차이는 auto-commit가 활성화되면 중요하게 된다. 왜냐하면 commit 메쏘드가 호출되어질 때 작용되기 때문이다. 첫 번째 경우에서, 각 SQL문은 개별적으로 커미트되어지고 두 번째 경우에서는 모든 것이 함께 커미트된다.

4.1.5 Statement 객체들내의 SQL Escape Syntax

Statement 객체들은 SQL escape 문장을 사용하는 SQL문들을 포함할 수 있다. escape 문장은 그것에 포함된 코드가 다르게 처리되어야하는 것을 드라이버에게 신호를 보낸다. 드라이버는 각 escape 문장을 검사하고 그것을 특정 데이터베이스가 이해하는 코드로 번역한다. 이것은 escape 문장을 DBMS에 독립적으로 만들고 프로그래머가 다른 방법으로 사용될 수 없는 현태를 이용하도록 해준다.

    escape 절는 중괄호와 키워드로 구분되어진다.

     {keyword . . . parameters . . . } 

    키워드는 아래에 제시한 escape 종류를 가리킨다.

  • LIKE escape문자들를 위한 escape

    문자 "%"와 "_"은 SQL LIKE 절들에서 와일드카드와 같이 동작된다. ("%"는 0 또는 이상의 문자들에 적용되고 "_"는 정확히 한문자에 적용된다.) 완전하게 그것들을 해석하기 위해서, "\"를 앞에 둘수 있다.

     {escape 'escape-character'} 

    예를 들어, escape문자로서 역슬래시를 사용하는 다음의 질의는 언더바로 시작되는 식별 이름을 찾는다.:

     stmt.executeQuery("SELECT name FROM Identifiers WHERE Id LIKE '\_%' {escape '\'}; 
  • 스칼라 기능을 위한 fn

    거의 모든 DBMS들은 숫자, 스트링, 시간, 날짜, 시스템 그리고 스칼라값에 대한 변환 함수들을 가진다.
    이러한 함수들중 하나는 키워드 fn 뒤에 원하는 함수 이름과 그것의 인자들을 가지고 escape 문장내에 포함하여 사용할 수 있다.
    예를 들어, 다음 코드는 결합되어질 두 개의 인자들을 가자는 concat 함수를 호출한다.:

     {fn concat("Hot", "Java")}; 

    현재 데이터베이스 사용자의 이름은 다음의 문장으로 얻을 수 있다.:

     {fn user()}; 

    스칼라 함수들은 조금 다른 문장을 가지고 다른 DBMS들에의해 지원되어지며 그것들은 모든 드라이버들에의해 지원되어지지는 않을 것이다.
    다양한 DatabaseMetaData 메쏘드는 지원되는 함수들을 나열한다.
    예를 들어, getNumericFuctions 메쏘드는 수치 함수들의 이름을 ","로 구분하여 나열하고, getStringFunctions 메쏘드는 스트링 함수들을 리턴한다.

    드라이버는 escaped 함수 호출을 적당한 문장에 매핑하거나 직접 함수 그자체를 구현한다.

  • 날짜와 시간 리터럴을 위한 d, t 그리고 ts

    DBMS들마다 날짜, 시간, 타임스탬프(timestamp) 리터럴에 사용되는 문장이 다르다.
    JDBC는 드라이버가 DBMS 표현으로 변환해야하는 escape절을 사용하여, 이러한 리터럴의 문장을위해 ISO 표준 포맷을 지원한다.

    예를 들어, 날짜는 JDBC SQL문내에서 다음의 문장으로 지정되어진다.:

     {d 'yyy-mm-dd'} 

    이 문장에서, yyyy는 연도이고, mm은 달, 그리고 dd는 일이다.
    드라이버는 escape절을 동등한 특정 DBMS 표현으로 대체할 것이다.
    예를 들어, 드라이버는 {d 1999-02-28}를 기본적인 데이터베이스를 위한 적당한 포맷이라면 '28-FEB-99'로 대체할 것이다.

    TIME과 TIMESTAMP를 위한 연속적인 escape 절들도 있다.:

     {t 'hh:mm:ss'} {ts 'yyyy-mm-dd hh:mm:ss.f . . .'} 

    TIMESTAMP의 아주 작은 초(.f . . .)의 부분은 생략할 수 있다.

  • 저장된 프로시져들을 위한 call 또는 ?=call

    만약 데이터베이스가 저장된 프로시져들을 지원한다면, 다음의 문법을가지고 JDBC에서 호출할 수 있다.:

     {call prodecure_name[(?, ?, ...)]} 

    또는, 프로시져가 결과 매개변수를 리턴할 수도 있다.

     {? = call procedure_name[(?, ? , ...)]} 

    사각 괄호는 그것들 사이에 포함되어진 것들이 선택적이라는 것을 나타낸다.

    입력 인자들은 리터럴들이거나 매개변수들중에 하나일 것이다. 더많은 정보는 Section 7, "CallableStatement"를 참조해라.

    데이터베이스가 저장 프로시져를 지원하는지를 검사하기 위해서는 DatabaseMetaData.supportsStroredProcedures 메쏘드를 호출하면 된다.

  • 외부 결합(outer join)을 위한 oj

    외부 결합을 위한 문법은 다음과 같다.

     {oj outer-join} 

    여기서 outer-join은 폼이다.

     table LEFT OUTER JOIN {table | outer-join} ON search-condition 

    외부 결합은 진보된 형태이고 그것들을 설명을 위한 SQL 문법을 확인할 수 있다. JDBC는 드라이버가 지원하는 외부 결합을 검사하기 위한 세가지 DatabaseMetaData 메쏘드들을 제공한다. : supportsOuterJoins, supportsFullOuterJoins 그리고 supportsLimitedOuterJoins.

    Statement.setEscapeProcessing 메쏘드는 escape 처리를 on하거나 off시키며 디폴트는 on이다. 프로그래머는 실행이 가장 많은 처리시간을 줄이기위해서 off 시킬수 있지만 보통은 on일 것이다. setEscapeProcessing은 그것이 호출되기도전에 SQL문장이 데이터베이스로 전송되어지기 때문에 PreparedStatement 객체를 위해서는 동작되지 않는다.
    사전 컴파일에 관해서는 PreparedStatement를 봐라.

'Study_Web > JSP' 카테고리의 다른 글

자바 자주쓰는 형변환  (0) 2008.02.18
이클립스 플러그인[펌]  (0) 2008.01.30
빈 태그  (0) 2008.01.29
PreparedStatement 와 Statement  (0) 2008.01.29
equal 과 “==”의 차이  (0) 2008.01.24