- xrath.com 에서 번역됨

[목차] [전의 항목] [다음의 항목]

## CallableStatement

주: 이 장의 내용은, Addison Wesley 사부터 Java 시리즈의 1 권으로서 출판된 「JDBCTM API Tutorial and Reference, Second Edition:Universal Data Access for the JavaTM 2 Platform」(ISBN 0-201-43328-1)에 근거해 작성한 것입니다.

### 7.1 CallableStatement 의 개요

`CallableStatement` 객체는, 모든 RDBMS 에 대해 표준적인 방법으로 스트아드프로시쟈를 호출하는 방법을 제공합니다. 스트아드프로시쟈는, 데이타베이스에 포함되어 스트아드프로시쟈에의 호출은,`CallableStatement` 객체가 보관 유지합니다. 이 호출은, 이스케이프 구문으로 쓰여집니다. 이 구문에는, 결과 파라미터를 수반하는 서식과 수반하지 않는 서식의 2 개의 서식이 있습니다. 결과 파라미터는 OUT 파라미터의 일종으로, 스트아드프로시쟈의 반환값입니다. 어느 쪽의 형식도, 입력 (IN 파라미터), 출력 (OUT 파라미터), 또는 그 양쪽 모두 (INOUT 파라미터)로서 사용하는 변수를 가질 수가 있습니다. 물음표는 파라미터의 플레이스홀더로서 사용할 수 있습니다.

JDBC API 를 사용해 스트아드프로시쟈를 호출하는 구문은, 다음과 같습니다. 꺽쇄묶음은, 거기에 둘러싸인 부분이 옵션인 것을 나타냅니다. 이러한 외모는, 그 자체 구문의 일부에서는 없습니다.

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

이하는, 결과 파라미터를 돌려주는 프로시저의 구문입니다.

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

파라미터가 붙지 않는 스트아드프로시쟈의 구문은, 이하와 같이 됩니다.

>     {call procedure_name}

일반적으로,`CallableStatement` 객체의 작성자는, 사용되고 있는 DBMS 가 스트아드프로시쟈를 지원하고 있는 것, 및 그러한 프로시저가 무엇인가 말하는 것을 알고 있습니다. 그러나, 확인이 필요한 경우는, 다양한 `DatabaseMetaData` 메소드가 이러한 정보를 제공합니다. 예를 들어, 메소드 `supportsStoredProcedures` 는, DBMS 가 스트아드프로시쟈 호출을 지원하는 경우,`true` 를 돌려주어, 메소드 `getProcedures` 는, 사용 가능한 스트아드프로시쟈의 설명을 돌려줍니다.

`CallableStatement` 는, SQL 후미카즈반을 처리하는 `Statement` 의 메소드를 상속해, 또 IN 파라미터를 처리하는 `PreparedStatement` 의 메소드를 상속합니다. ``CallableStatement` 에 정의 떠날 수 있어 모든 메소드는, OUT 파라미터 또는 INOUT 파라미터의 OUT 부분의 처리 (OUT 파라미터의 JDBC 의 형태의 등록, 그러한 값의 꺼내, 또는 반환값이 JDBC `NULL` 였는지 어떠했는지의 확인)를 실시합니다. `ResultSet` 에 정의된 `getXXX` 메소드가 결과 세트로부터의 값을 꺼내는데 대해,`CallableStatement` 에 정의된 `getXXX` 메소드는 OUT 파라미터로부터 값을 꺼내는지, 스트아드프로시쟈의 값을 돌려주든가, 혹은 그 양쪽 모두를 실시합니다.`

#### 7.1. 1 CallableStatement 객체의 생성

`CallableStatement` 객체는,`Connection` 메소드의 `prepareCall` 에 의해 생성됩니다. 다음의 예에서는,`CallableStatement` 의 인스턴스가 생성됩니다. con 는 액티브한 JDBC 의 `Connection` 객체입니다.

>     CallableStatement cstmt = con.prepareCall(
>     	"{call getTestData(?, ? )}");

변수 cstmt 에는, 스트아드프로시쟈 `getTestData` 의 호출이 포함되어 있습니다. 이 스트아드프로시쟈에는, 2 개의 입력 파라미터가 지정되어 결과 파라미터는 지정되고 있지 않습니다. `?` 플레이스홀더가, IN, OUT, 또는 INOUT 파라미터의 어느 것으로 될까는, 스트아드프로시쟈 `getTestData` 에 의존합니다. `CallableStatement` 객체의 이 인스턴스는, JDBC 1.0 API 를 사용해 생성되고 있기 (위해)때문에, cstmt 에 의해 불려 가는 스트아드프로시쟈내의 쿼리는, 모두 디폴트의 `ResultSet` 객체 (스크롤 및 갱신을 실시할 수가 없는 객체)를 생성합니다.

JDBC 2.0 API 에서는,`CallableStatement` 객체를 생성해, 그 객체로부터, 스크롤 및 갱신을 실시할 수가 있는 `ResultSet` 객체를 생성할 수 있습니다. 다음의 코드를 참조해 주세요.

>     String sql = "{call getTestData(?, ? )}";
>     CallableStatement cstmt2 = con.prepareCall(sql,
>     	ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

변수 cstmt2 에는, cstmt 와 같게, 스트아드프로시쟈 `getTestData` 의 호출이 포함되어 있습니다. 다만 cstmt2 의 경우,`getTestData` 에 의해 생성된 `resultSet` 객체는 어떤 것에서도, 모두 갱신 및 스크롤을 실시할 수가 있습니다 (그렇지만, 열리고 있는 동안에 행해진 변경은 반영되지 않습니다 ). 스크롤 및 갱신을 실시할 수가 있을지 어떨지를 식별할 경우에 사용하는 정수에 대해서는, 「ResultSet」의 장을 참조해 주세요.

#### 7.1. 2 IN 파라미터

IN 파라미터의 값의 `CallableStatement` 객체에의 인도는,`PreparedStatement` 로부터 상속된 `setXXX` 메소드를 사용해 행해집니다. 건네받는 값의 형태는, 어느 `setXXX` (`float` 의 값을 건네주기 위해서(때문에)는 `setFloat`,`boolean` 의 값을 건네주기 위해서(때문에)는 `setBoolean` 등)를 사용할까에 의해 정해집니다. 파라미터를 사용하는 프로그램에서는, 많은 경우, IN 파라미터만이 사용됩니다.

#### 7.1. 3 배치 갱신의 실행

`CallableStatement` 객체의 배치 갱신은,`PreparedStatement` 객체와 같게 행해집니다. 실제,`CallableStatement` 객체의 기능은,`PreparedStatement` 객체의 기능과 같은 제한을 받습니다. 즉, 배치 갱신 기능을 사용할 때는,`CallableStatement` 객체는, 입력 파라미터를 지정하는 것도 깔고는 파라미터를 전혀 지정하지 않는, 스트아드프로시쟈 밖에 호출할 수 없습니다. 게다가 그 스트아드프로시쟈는, 갱신 카운트를 돌려주지 않으면 안됩니다. 스트아드프로시쟈가 갱신 카운트 이외의 결과를 돌려주거나 스트아드프로시쟈가 OUT 또는 INPUT 파라미터를 취하는 경우는,`CallableStatement.executeBatch` 메소드 (`PreparedStatement` 로부터 상속)는,`BatchUpdateException` 를 throw 합니다.

다음의 코드에서는, 배치 갱신 기능을 사용해, 2 개의 파라미터를 `CallableStatement` 객체에 관련짓고 있습니다.

>     CallableStatement cstmt = con.prepareCall(
>     			"{call updatePrices(?, ? )}");
>     cstmt.setString(1, "Colombian");
>     cstmt.setFloat(2, 8.49f);
>     cstmt.addBatch();

>     cstmt.setString(1, "Colombian_Decaf");
>     cstmt.setFloat(2, 9.49f);
>     cstmt.addBatch();

>     int [] updateCounts = cstmt.executeBatch();

변수 cstmt 에는, 스트아드프로시쟈 `updatePrices` 에의 호출이 포함되어 있습니다. 스트아드프로시쟈에는, 2 개의 파라미터를 관련지을 수 있고 있습니다. cstmt 를 실행하면(자), 2 개의 갱신문이, 배치로 해 정리해 실행됩니다. 한편의 갱신문에는,`Colombian` 및 `8.49f` 가 파라미터로서 지정되고 있습니다. 이제(벌써) 한편의 갱신문에는,`Colombian_Decaf` 및 `9.49f` 가 파라미터로서 지정되고 있습니다. `8.49f` 와 같이, 수치의 후에 `f` 가 지정되고 있는 경우는, 그 수치가 `float` 인 것을 Java 컴파일러에게 전하고 있습니다. `f` 가 지정되어 있지 않은 경우, 컴파일러는 10 진수의 수치를 `double` 라고 보므로,`float` 로서의 사용이 용서되지 않습니다.

#### 7.1. 4 OUT 파라미터

스트아드프로시쟈가 OUT 파라미터를 돌려주는 경우, 각 OUT 파라미터의 JDBC 의 형태는 `CallableStatement` 를 사용하기 전에 등록할 필요가 있습니다. 이 등록이 필요한 것은, 일부의 DBMS 에서는, SQL 형 ( JDBC 형이 나타내고 있습니다 )이 필요하기 때문에입니다. JDBC 가 필요로 하고 있는 것은 아닙니다. JDBC 의 데이터형, 사용 빈도의 높은 SQL 의 데이터형을 나타내는 총칭 SQL 의 형태 식별자에 대한 자세한 것은,「SQL 와 Java 의 형태의 매핑」을 참조해 주세요.

JDBC 의 형태의 등록은, 메소드 `registerOutParameter` 에 의해 실시합니다. 문장의 실행이 완료하고 나서,`CallableStatement` 의 `getXXX` 메소드를 사용해 OUT 파라미터의 값을 가져옵니다. 사용에 적절한 `CallableStatement`. `getXXX` 메소드는, 그 OUT 파라미터에 등록되어 있는 JDBC 의 형태에 대응하는 Java 프로그램 언어의 형태의 메소드입니다 (JDBC 의 형태로부터 Java 의 형태에의 표준 매핑에 대해서는,표 8.1 을 참조). 즉,`registerOutParameter` 는, (그것이 데이타베이스가 돌려주는 데이터의 형태에 일치하도록(듯이)) JDBC 의 형태를 사용해,`getXXX` 가 그것을 Java 의 형태에 캐스트 합니다.

예를 들어 설명하면(자), 다음의 코드는 OUT 파라미터를 등록해, cstmt 가 호출하는 스트아드프로시쟈를 실행하고 나서, OUT 파라미터에 반환된 값을 꺼냅니다. 메소드 `getByte` 는, 최초의 OUT 파라미터로부터 Java 의 `byte` 를 꺼내,`getBigDecimal` 는, 2 번째의 OUT 파라미터로부터 `java.math.BigDecimal` 객체 (소수점 이하 제 3 위까지)를 꺼냅니다. cstmt 에 의해 불려 간 스트아드프로시쟈가 결과 세트를 돌려주므로, cstmt 의 실행에는 `executeQuery` 메소드를 사용하고 있습니다.

>     CallableStatement cstmt = con.prepareCall(
>     	"{call getTestData(?, ? )}");
>     cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
>     cstmt.registerOutParameter(2, java.sql.Types.DECIMAL, 3);
>     ResultSet rs = cstmt.executeQuery();
>     // .  .  .  retrieve result set values with rs.getXXX methods
>     byte x = cstmt.getByte(1);
>     java.math.BigDecimal n = cstmt.getBigDecimal(2);

`ResultSet` 과는 달리,`CallableStatement` 에서는, 큰 OUT 치를 조금씩 차례차례로 취득하기 위한 특별한 기구는 제공되고 있지 않습니다. 즉,`getAsciiStream` 또는 `getBinary-Stream` 등의 데이터 스트림을 취득하는 것 같은 `getXXX` 메소드를 가지고 있지 않습니다. 다만, JDBC 2.0 API 의 `CallableStatement` 의 메소드에서는, OUT 파라미터 또는 INOUT 파라미터로서 SQL3 의 데이터형을 취득할 수가 있습니다. `CallableStatement` 에는,`getBlob` 메소드 및 `getClob` 메소드가 짜넣어지고 있어 바이너리 라지 객체 및 캐릭터 라지 객체를 취득할 수가 있습니다.

#### 7.1. 5 파라미터의 번호 붙어라

대상 파라미터를 지정하는 `int` 를 인수에 취하는 메소드 (`setXXX`,`getXXX`, 및 `registerOutParameter`)의 경우, 그 `int` 는,`?` 플레이스홀더 파라미터만을 참조합니다. 그 int 는 1 으로부터 셀 수 있습니다. 이 파라미터의 번호는, 스트아드프로시쟈 호출로 지정되는 리터럴 파라미터를 참조하지 않습니다. 예를 들어, 다음의 코드는, 1 개의 리터럴 파라미터 ( `25` )와 1 개의 `?` 파라미터를 가지는 스트아드프로시쟈 호출의 예입니다.

>     CallableStatement cstmt = con.prepareCall(
>     		"{call getTestData(25, ? )}");
>     cstmt.registerOutParameter(1, java.sql.Types.TINYINT);

이 코드에서는,`registerOutParameter` 의 제 1 인수인 `int` `1` 은, 최초의 `?` 파라미터 (여기에서는 `?` 파라미터는 1 개 밖에 없습니다)를 참조하고 있습니다. 이 `int 1` 은, 스트아드프로시쟈의 제 1 파라미터인 리터럴의 `25` 를 참조하고 있는 것은 아닙니다.

#### 7.1. 6 INOUT 파라미터

입력을 공급해, 출력을 받는 파라미터는, 메소드 `registerOutParameter` 를 호출하는 것 외에, (`PreparedStatement`로부터 상속된) 적절한 `setXXX`를 호출할 필요가 있습니다. `setXXX` 메소드는, 파라미터의 값을 입력 파라미터로 설정해, 메소드 `registerOutParameter` 가 그 JDBC 의 형태를 출력 파라미터로서 등록합니다. ``setXXX` 메소드는, Java 의 값을 제공합니다. 드라이버는 그 값을 데이타베이스에 송신하기 전에 JDBC 의 값으로 변환합니다. 이 IN 의 값의 JDBC 의 형태와 메소드 `registerOutParameter` 에 공급하는 JDBC 의 형태는 동일하지 않으면 안됩니다. 그리고, 출력치를 꺼내기 위해서(때문에)는, 대응하는 `getXXX` 메소드를 사용합니다. 예를 들어, 파라미터의 Java 의 형태가 `byte` 의 경우는,`setByte` 메소드를 사용해 입력치를 대입해,`TINYINT` 를 JDBC 의 형태로서 `registerOutParameter` 에 건네주어,`getByte` 를 사용해 출력치를 꺼낼 필요가 있습니다 (형태의 매핑의 일람에 대해서는,「SQL 와 Java 의 형태의 매핑」을 참조).`

이하의 예에서는, 스트아드프로시쟈 `reviseTotal` 가 있어, 그 유일한 파라미터가 1 개의 INOUT 파라미터인 경우를 상정하고 있습니다. 메소드 `setByte` 는 이 파라미터를 `25` 로 설정해, 드라이버는 이것을 JDBC 의 `TINYINT` 로서 후에 데이타베이스에 송신합니다. 다음의 `registerOutParameter` 는, 이 파라미터를 JDBC 의 `TINYINT` 로서 등록합니다. 스트아드프로시쟈가 실행되면(자), 새로운 JDBC `TINYINT` 의 값이 돌려주어져 메소드 `getByte` 가 이 새로운 값을 Java 의 `byte` 로서 꺼냅니다. 이 예로 불려 가고 있는 스트아드프로시쟈는 갱신 카운트를 돌려주기 (위해)때문에,`executeUpdate` 메소드가 사용되고 있습니다.

>     CallableStatement cstmt = con.prepareCall(
>     		"{call reviseTotal(? )}");
>     cstmt.setByte(1, (byte) 25);
>     cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
>     cstmt.executeUpdate();
>     byte x = cstmt.getByte(1);

#### 7.1. 7 결과 세트의 뒤에 OUT 파라미터를 꺼낸다

일부의 DBMS 에 부과되어 있는 제한을 위해, 이식성을 크게 하기 위해서 다음을 추천 합니다. OUT 파라미터를 꺼내기 전에,`CallableStatement` 객체의 실행에 의해 생성된 `ResultSet` 객체의 모든 결과를 꺼내 주세요. 결과 세트의 값이 모두 꺼내지면(자), `ResultSet.next` 메소드는 `false` 를 돌려줍니다.

`CallableStatement` 객체가 복수의 `ResultSet` 객체를 돌려주는 경우 (`execute` 메소드의 호출에 의해 실행되었을 경우만 일어날 수 있다), OUT 파라미터를 꺼내기 전에, 모든 결과를 꺼낼 필요가 있습니다. 이 경우, 모든 결과에 확실히 액세스 하도록(듯이), 결과가 없어질 때까지 `Statement` 의 메소드 `getResultSet`,`getUpdateCount`, 및 `getMoreResults` 를 호출할 필요가 있습니다. 모든 결과가 없어진 후에,`getMoreResults` 메소드를 호출하면(자) `false` 가 돌려주어져`getUpdateCount` 메소드를 호출하면(자) `-1` 가 돌려주어집니다.

`ResultSet.getXXX` 메소드를 사용해 `ResultSet` 객체로부터 모든 값이 꺼내져 갱신 카운트가 돌려주어지고 없어지면(자),`CallableStatement`. `getXXX` 메소드를 사용해 OUT 파라미터의 값을 꺼낼 수가 있습니다.

#### 7.1. 8 NULL 치를 OUT 파라미터로서 꺼낸다

OUT 파라미터에 반환되는 값은 JDBC `NULL` 인 경우가 있습니다. JDBC `NULL` 치는,`getXXX` 메소드가 돌려주는 값이 `getXXX` 메소드의 형태에 의해 `null`,`0`,`false` 의 어떤 것인가가 되도록(듯이) 변환됩니다. `ResultSet` 객체에 대해,`0` 또는 `false` 의 값이 원래 JDBC `NULL` 였는지의 여부를 아는 유일한 방법은, `wasNull` 메소드를 사용해 확인하는 방법입니다. `wasNull` 는,`getXXX` 메소드가 읽어낸 마지막 값이 JDBC `NULL` 의 경우 `true` 를 돌려주어, 그렇지 않은 경우 `false` 를 돌려줍니다.

[목차] [전의 항목] [다음의 항목]

Copyright © 1999, Sun Microsystems, Inc. All rights reserved.