ヘッダーをスキップ
Oracle Database 2日でJava開発者ガイド
11g リリース2(11.2)
B56268-02
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

6 アプリケーションの拡張: 拡張JDBC機能

この章では、Javaアプリケーションで使用できる追加機能について説明します。一部の機能でサンプル・アプリケーションに実装されていないものもありますが、パフォーマンスを向上させるためにコード内で使用できる機能拡張もあります。

この章は次の項で構成されています。

6.1 動的SQLの使用

本番環境では、動的SQL、つまり即時にSQL文を生成することが常に必要です。特に、データベースに対して行われる更新の場合など、最終的な問合せが実行時までわからないことがよくあります。

異なる更新値を持つ多数の類似問合せをデータベースに対して実行する必要がある場合は、Statementオブジェクトを拡張するOraclePreparedStatementオブジェクトを使用できます。この場合、リテラルの更新値をバインド変数に置き換えます。また、OracleCallableStatementオブジェクトを介してストアド・プロシージャをコールすることによって、データベースでPL/SQLストアド・ファンクションを使用することもできます。

この項では、次の項目について説明します。

6.1.1 OraclePreparedStatementの使用

データベースに対して静的SQL問合せを実行する場合は、Statementオブジェクトを使用します。ただし、複数の類似問合せを実行したり、データベースの多数の列に影響する複数の更新を実行する場合は、それぞれの問合せをアプリケーションにハード・コードすることはできません。

同じSQL文を複数回実行する場合は、OraclePreparedStatementを使用できます。次のような問合せについて考えてみます。

SELECT * FROM Employees WHERE ID=xyz;

この問合せのxyzの値が変更されるたびに、SQL文を再度コンパイルする必要があります。

OraclePreparedStatement機能を使用すると、実行するSQL文はプリコンパイルされてPreparedStatementオブジェクトに格納されるため、実行するたびにコンパイルしなくても、何度でも実行できます。文中のデータが変化する場合は、そのデータのプレースホルダとしてバインド変数を使用し、実行時にリテラル値を指定することができます。

OraclePreparedStatementの使用について、次に例を示します。

例6-1 PreparedStatementの作成

OraclePreparedStatement pstmt = conn.prepareStatement("UPDATE Employees 
                                SET salary = ? WHERE ID = ?");
   pstmt.setBigDecimal(1, 153833.00)
   pstmt.setInt(2, 110592)   

OraclePreparedStatementインタフェースを使用するメリットは、次のとおりです。

  • 同じPreparedStatementオブジェクトを使用することによって、更新をバッチ化できます。

  • 何度も実行されるSQL文を1回目の実行時にのみコンパイルするため、パフォーマンスを改善できます。

  • バインド変数を使用して、コードを単純かつ再利用可能にすることができます。

6.1.2 OracleCallableStatementの使用

OracleCallableStatementインタフェースを使用すると、データベース上のストアド・プロシージャにアクセスできます。このインタフェースは、OraclePreparedStatementインタフェースを拡張します。OracleCallableStatementインタフェースは、ストアド・プロシージャをコールするために、標準的なJDBCエスケープ構文で構成されています。このインタフェースは、結果パラメータの有無にかかわらず使用できます。ただし、結果パラメータを使用する場合は、それがOUTパラメータとして登録されている必要があります。このインタフェースでは、その他のパラメータとして、INまたはOUTあるいはその両方を使用できます。

これらのパラメータは、OraclePreparedStatementインタフェースから継承されるアクセッサ・メソッドの使用によって設定されます。INパラメータはsetXXXメソッドで設定し、OUTパラメータはgetXXXメソッドで取得します。XXXは、パラメータのJavaデータ型です。

また、CallableStatementは、複数のResultSetオブジェクトを返すこともあります。

例として、次のようにOracleCallableStatementを作成して、fooストアド・プロシージャをコールすることができます。

例6-2 CallableStatementの作成

OracleCallableStatement cs = (OracleCallableStatement)
conn.prepareCall("{call foo(?)}");

次のいずれかの方法で、文字列barをこのプロシージャに渡すことができます。

cs.setString(1,"bar"); // JDBC standard
// or...
cs.setStringAtName(X, "value"); // Oracle extension

6.1.3 バインド変数の使用

バインド変数は、SQL文中のリテラルのかわりとなる変数です。バインド変数をOraclePreparedStatementおよびOracleCallableStatementとともに使用して、SQL文の構築に使用されるパラメータ値を指定します。バインド変数を使用すると、本番環境でのパフォーマンスが大幅に向上します。

PL/SQLブロックまたはストアド・プロシージャ・コールでは、INOUTおよびIN OUTという修飾子を使用して、入力変数と出力変数を区別できます。入力変数の値はsetXXXメソッドで設定し、OUT変数の値はgetXXXメソッドで取得します。XXXは、値のJavaデータ型です。これは、アクセスするデータベース内の列のSQLデータ型によって異なります。

6.2 ストアド・プロシージャのコール

Oracle Java Database Connectivity(JDBC)ドライバでは、PL/SQLストアド・プロシージャおよび無名ブロックの処理がサポートされています。Oracle JDBCドライバでは、Oracle PL/SQLブロック構文およびほとんどのJDBCエスケープ構文がサポートされています。次のPL/SQLコールは、すべてのOracle JDBCドライバで動作します。

例6-3 ストアド・プロシージャのコール

// JDBC syntaxCallableStatement cs1 = conn.prepareCall
                        ( "{call proc (?,?)}" ) ; // stored proc
CallableStatement cs2 = conn.prepareCall
                        ( "{? = call func (?,?)}" ) ; // stored func

// Oracle PL/SQL block syntax
CallableStatement cs3 = conn.prepareCall
                        ( "begin proc (?,?); end;" ) ; // stored proc
CallableStatement cs4 = conn.prepareCall
                        ( "begin ? := func(?,?); end;" ) ; // stored func

Oracle構文の例として、ストアド・ファンクションを作成するPL/SQLコードの一部を示します。このPL/SQLファンクションでは文字列を取得して接尾辞を連結します。

例6-4 ストアド・ファンクションの作成

create or replace function foo (val1 char)
return char as
begin
return val1 || 'suffix';
end;

次のように、Javaプログラムでこのストアド・ファンクションをコールできます。

例6-5 Javaのストアド・ファンクションのコール

OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:thin:@<hoststring>");
ods.setUser("hr");
ods.setPassword("hr");
Connection conn = ods.getConnection();
CallableStatement cs = conn.prepareCall ("begin ? := foo(?); end;");
cs.registerOutParameter(1,Types.CHAR);
cs.setString(2, "aa");
cs.executeUpdate();
String result = cs.getString(1);

次の項では、このマニュアルのサンプル・アプリケーションでストアド・プロシージャを使用する方法について説明します。

6.2.1 JDeveloperでのPL/SQLストアド・プロシージャの作成

JDeveloperを使用すると、データベース・ナビゲータを使用して、ストアド・プロシージャをデータベースに作成できます。次の手順では、サンプル・アプリケーションで従業員レコードを挿入するための代替方法として使用できるストアド・プロシージャを作成します。

  1. Select the 「DatabaseNavigatorName」タブを選択して、データベース・ナビゲータを表示します。

  2. データベース接続ノード(デフォルトではConnection1)を開き、HRデータベース内のオブジェクトを表示します。

  3. 「プロシージャ」を右クリックし、「新規プロシージャ」を選択します。

  4. 「PL/SQLプロシージャ作成」ダイアログ・ボックスで、オブジェクト名としてinsert_employeeと入力します。「OK」をクリックします。

    プロシージャのスケルトン・コードがソース・エディタに表示されます。

  5. プロシージャ名の後に、次のコード行を入力します。

    PROCEDURE    "INSERT_EMPLOYEE" (p_first_name  employees.first_name%type, 
      p_last_name    employees.last_name%type,
      p_email        employees.email%type,
      p_phone_number employees.phone_number%type,
      p_job_id       employees.job_id%type,
      p_salary       employees.salary%type
    ) 
    
  6. BEGIN文の後のNULLを示す行を次の内容で置き換えます。

      INSERT INTO Employees VALUES (EMPLOYEES_SEQ.nextval, p_first_name , 
        p_last_name , p_email , p_phone_number, SYSDATE, p_job_id, 
        p_salary,.30,100,80);
    

    この文では、DataHandler.javaクラスのaddEmployeeメソッドの最後の3行に使用される、ハードコードされた同じ値が使用されていることがわかります。

  7. END文にプロシージャ名を追加します。

    END insert_employee;
    
  8. ファイルを保存し、コンパイル・エラーがないかを確認します。

例6-6に、ストアド・プロシージャの完成したコードに示します。

例6-6 従業員データを挿入するためのPL/SQLストアド・プロシージャの作成

PROCEDURE    "INSERT_EMPLOYEE" (p_first_name  employees.first_name%type, 
  p_last_name    employees.last_name%type,
  p_email        employees.email%type,
  p_phone_number employees.phone_number%type,
  p_job_id       employees.job_id%type,
  p_salary       employees.salary%type
) 
AS
BEGIN
  INSERT INTO Employees VALUES (EMPLOYEES_SEQ.nextval, p_first_name , 
    p_last_name , p_email , p_phone_number, SYSDATE, p_job_id, 
    p_salary,.30,100,80);
END insert_employee;

6.2.2 ストアド・プロシージャを使用するためのメソッドの作成

次の手順では、addEmployeeメソッドのかわりに使用できるメソッドをDataHandler.javaクラスに追加します。ここで追加する新しいメソッドでは、insert_employeeストアド・プロシージャを使用します。

  1. 「アプリケーション」タブを選択して、アプリケーション・ナビゲータを表示します。

  2. DataHandler.javaファイルがJavaソース・エディタでまだ開いていない場合は、ダブルクリックして開きます。

  3. 次のようにCallableStatementをインポートします。

    import java.sql.CallableStatement;
    
  4. addEmployeeメソッドの後に、addEmployeeSPメソッドの宣言を追加します。

    public String addEmployeeSP(String first_name, String last_name, 
      String email, String phone_number, String job_id,
      int salary) throws SQLException {
    }
    

    このメソッドのシグネチャはaddEmployeeのものと同じです。

  5. このメソッド内にtryブロックを追加し、このブロック内でデータベースに接続します。

    try {
      getDBConnection(); 
    }
    
  6. さらに、tryブロック内で次のSQL文字列を作成します。

    sqlString = "begin hr.insert_employee(?,?,?,?,?,?); end;";
    

    文中の疑問符(?)はバインド変数で、ストアド・プロシージャによって使用される、first_namelast_nameなどの値のプレースホルダの役割を果たします。

  7. CallableStatementを作成します。

    CallableStatement callstmt = conn.prepareCall(sqlString);
    
  8. INパラメータを設定します。

      callstmt.setString(1, first_name);
      callstmt.setString(2, last_name);
      callstmt.setString(3, email);
      callstmt.setString(4, phone_number);
      callstmt.setString(5, job_id);
      callstmt.setInt(6, salary);
    
  9. トレース・メッセージを追加し、コール可能文を実行します。

      System.out.println("\nInserting with stored procedure: " + 
                          sqlString);
      callstmt.execute();
    
  10. 戻りメッセージを追加します。

      return "success"; 
    
  11. tryブロックの後にcatchブロックを追加して、すべてのエラーを捕捉します。例5-5で作成したlogExceptionをコールします。

    catch ( SQLException ex ) {
      System.out.println("Possible source of error: Make sure you have created the stored procedure"); 
      logException( ex ); 
      return "failure";
    }
    
  12. DataHandler.javaを保存します。

例6-7に、完成したメソッドを示します。


注意:

logException()メソッド(例5-5を参照)を追加していない場合は、logException(ex)の下に表示される赤い波線によってエラーが示されます。ファイルのコンパイルに進む前に、このメソッドがDataHandler.javaクラスに存在する必要があります。

例6-7 JavaでのPL/SQLストアド・プロシージャの使用

public String addEmployeeSP(String first_name, String last_name, 
  String email, String phone_number, String job_id,
  int salary) throws SQLException {
 
  try {
    getDBConnection(); 
    sqlString = "begin hr.insert_employee(?,?,?,?,?,?); end;";
    CallableStatement callstmt = conn.prepareCall(sqlString);
    callstmt.setString(1, first_name);
    callstmt.setString(2, last_name);
    callstmt.setString(3, email);
    callstmt.setString(4, phone_number);
    callstmt.setString(5, job_id);
    callstmt.setInt(6, salary);
    System.out.println("\nInserting with stored procedure: " + 
                       sqlString);
 
    callstmt.execute();
    return "success"; 
  }
  catch ( SQLException ex ) {
    System.out.println("Possible source of error: Make sure you have created the stored procedure"); 
    logException( ex ); 
    return "failure";
  }
}

6.2.3 ユーザーによるストアド・プロシージャの選択の許可

この項の手順では、insert.jspページにラジオ・ボタンを追加します。従業員を挿入する場合に、ストアド・プロシージャを使用するか、またはJavaコードでSQL問合せを使用するかを、このラジオ・ボタンによって、ユーザーが選択できるようにします。

  1. insert.jspを開いていない場合は、ビジュアル・エディタで開きます。

  2. 「Insert Employee Record」という見出しの後に、新しい行を作成します。この新しい行にカーソルを置き、「UseBean」をコンポーネント・パレットの「JSP」ページからドラッグしてjsp:useBeanタグをこのページに追加します。IDとしてempsbeanを入力し、「クラス」としてhr.DataHandlerを参照して選択し、「有効範囲」「セッション」に設定します。ページ上でUseBeanが選択されている状態で、この行のスタイルをHeading 3ではなくNoneに設定します。

  3. 「Radio Button」コンポーネントをコンポーネント・パレットの「HTML Forms」ページから表の上にあるフォーム内のページにドラッグします。「ラジオ・ボタンの挿入」ダイアログ・ボックスで、「名前」useSPを入力し、「値」falseを入力して、「チェック」を選択します。「OK」をクリックします。

  4. ビジュアル・エディタでボタンの右側にカーソルを置き、「新しいレコードの追加にはJDBCのみを使用する」など、ボタンの目的を説明するテキストを入力します。

  5. 現在の行の末尾で[Enter]を押して、新しい行を作成します。

  6. 2つ目の「Radio Button」を最初のラジオ・ボタンの下にドラッグします。「ラジオ・ボタンの挿入」ダイアログ・ボックスで、「名前」useSPを入力し、「値」trueを入力して、「チェック」チェック・ボックスが選択されていないことを確認します。

  7. ビジュアル・エディタでボタンの右側にカーソルを置き、「レコードの追加にはJDBCからコールするストアド・プロシージャのみを使用する」など、ボタンの目的を説明するテキストを入力します。

  8. ページを保存します。

図6-1に、ストアド・プロシージャを使用するときのオプションとなるラジオ・ボタンのあるinsert.jsp を示します。

図6-1 ストアド・プロシージャ・オプションのためのリンクの追加

図6-1の説明が続きます。
「図6-1 ストアド・プロシージャ・オプションのためのリンクの追加」の説明

6.2.4 アプリケーションからのストアド・プロシージャのコール

この項の手順では、insert.jspページ上でフォームを処理するinsert_action.jspファイルを変更し、ラジオ・ボタンの選択によって、新しい従業員レコードを挿入するための適切なメソッドを選択します。

  1. insert_action.jspを開いていない場合は、ビジュアル・エディタで開きます。

  2. スクリプトレットをダブルクリックして「スクリプトレットのプロパティ」ダイアログ・ボックスを表示し、次のようにsalary変数の後に新しい変数を追加します。

    String useSPFlag = request.getParameter("useSP");
    
  3. 「スクリプトレットのプロパティ」ダイアログ・ボックスのまま、その下で、既存のempsbean.addEmployee行を次のコード行で置き換えます。このコード行では、addEmployeeSPメソッドまたはpure JDBC addEmployeeメソッドを選択してレコードを挿入します。

    if ( useSPFlag.equalsIgnoreCase("true"))
      empsbean.addEmployeeSP(first_name, last_name, email, 
      phone_number, job_id, salary.intValue()); 
    // otherwise use pure JDBC insert
    else
      empsbean.addEmployee(first_name, last_name, email, 
      phone_number, job_id, salary.intValue()); 
    
  4. insert_action.jspを保存します。

これで、アプリケーションを実行すると、挿入ページのラジオ・ボタンを使用して新しい従業員レコードを挿入する方法を選択できます。ブラウザでは、ページは図6-2のように表示されます。

図6-2 レコードを入力するためのストアド・プロシージャの使用

図6-2の説明が続きます。
「図6-2 レコードを入力するためのストアド・プロシージャの使用」の説明

6.3 カーソル変数の使用

Oracle JDBCドライバではREF CURSOR型のカーソル変数がサポートされますが、これはJDBC標準の一部ではありません。REF CURSOR型は、JDBC結果セットとしての使用がサポートされています。

カーソル変数は、問合せ作業領域の(内容でなく)メモリーの場所を保持します。カーソル変数を宣言すると、ポインタが作成されます。SQLでは、ポインタはデータ型REF xを取ります。ここで、REFREFERENCEの省略形で、xは参照されるエンティティを表します。次に、REF CURSORがカーソル変数への参照を特定します。多くの作業領域を参照する多くのカーソル変数が存在する可能性があるため、REF CURSORは、異なる多くの型のカーソル変数を識別するカテゴリまたはデータ型指定子と考えることができます。基本的にREF CURSORは問合せ結果をカプセル化します。

Oracleは結果セットを返しません。問合せによって返されたデータにアクセスするには、CURSORおよびREF CURSORを使用します。CURSORには、問合せ結果およびメタデータが含まれます。REF CURSOR(CURSOR変数)データ型には、カーソルへの参照が含まれます。RDBMSとクライアント、またはデータベースでPL/SQLとJavaの間での受け渡しが可能です。問合せまたはストアド・プロシージャから返される場合もあります。


注意:

REF CURSORインスタンスはスクロールできません。

この項では、次の項目について説明します。

6.3.1 OracleのREF CURSOR型のカテゴリ

カーソル変数を作成するには、REF CURSORカテゴリに属する型を識別することから開始します。次に例を示します。

dept_cv DeptCursorTyp 
...

次に、DeptCursorTyp型であることを宣言して、カーソル変数を作成します。

例6-8 REF CURSOR型の宣言

DECLARE TYPE DeptCursorTyp IS REF CURSOR

REF CURSORは、特定のデータ型というよりも、データ型のカテゴリです。ストアド・プロシージャは、REF CURSORカテゴリのカーソル変数を返すことがあります。この出力は、データベース・カーソルまたはJDBC結果セットと同等です。

6.3.2 REF CURSORデータへのアクセス

Javaでは、REF CURSORResultSetオブジェクトとしてマテリアライズされ、次のようにアクセスできます。

例6-9 JavaにおけるREF CURSORデータへのアクセス

import oracle.jdbc.*;
...
CallableStatement cstmt;
ResultSet cursor;

// Use a PL/SQL block to open the cursor
cstmt = conn.prepareCall
         ("begin open ? for select ename from emp; end;");

cstmt.registerOutParameter(1, OracleTypes.CURSOR);
cstmt.execute();
cursor = ((OracleCallableStatement)cstmt).getCursor(1);

// Use the cursor like a normal ResultSet
while (cursor.next ())
    {System.out.println (cursor.getString(1));} 

前述の例では、次の手順が実行されます。

  1. 接続クラスのprepareCallメソッドを使用して、CallableStatementオブジェクトが作成されます。

  2. コール可能文によって、REF CURSORを返すPL/SQLプロシージャが実装されます。

  3. 通常どおり、コール可能文の出力パラメータは、その型を定義するために登録されている必要があります。REF CURSORには、型コードOracleTypes.CURSORを使用します。

  4. コール可能文が実行され、REF CURSORが返されます。

  5. getCursorメソッドを使用するために、CallableStatementオブジェクトがOracleCallableStatementにキャストされます。このメソッドは、標準JDBC Application Program Interface(API)に対するOracleの拡張機能であり、REF CURSORResultSetオブジェクトに返します。

6.3.3 サンプル・アプリケーションでのREF CURSORの使用

次の項では、サンプル・アプリケーションを拡張し、新しい従業員レコードを挿入するときに、動的に生成された職務IDと職務名のリストを「ジョブ」フィールドに表示します。

これを行うには、REF CURSORを使用して、職務の結果セットをJobs表から取得するデータベース・ファンクションGET_JOBSを作成します。新しいJavaメソッドgetJobsは、このデータベース・ファンクションをコールして結果セットを取得します。

6.3.3.1 データベースでのパッケージの作成

次の手順では、データベースで新しいパッケージを作成して、REF CURSOR宣言を保持します。

  1. 「DatabaseNavigatorName」タブを選択して、ナビゲータで表示します。

  2. Connection1ノードを開いて、データベース・オブジェクトのリストを表示します。「パッケージ」にスクロールします。「パッケージ」を右クリックし、「新規パッケージ」を選択します。

  3. 「PL/SQLパッケージ作成」ダイアログ・ボックスで、名前としてJOBSPKGと入力します。「OK」をクリックします。パッケージの定義がソース・エディタに表示されます。

  4. 最初の行の末尾にカーソルを置き、[Enter]を押して新しい行を作成します。新しい行で、次のようにREF CURSORを宣言します。

        TYPE ref_cursor IS REF CURSOR;
    
  5. パッケージを保存します。

例6-10に、パッケージのコードを示します。

例6-10 データベースでのパッケージの作成

PACKAGE "JOBSPKG" AS
    TYPE ref_cursor IS REF CURSOR;
END;

6.3.3.2 データベース・ファンクションの作成

次の手順では、REF CURSORを使用して、職務の結果セットをJobs表から取得するデータベース・ファンクションGET_JOBSを作成します。

  1. データベース・ナビゲータで、必要なノードを再度開いて、HRデータベースのオブジェクトを表示します。「ファンクション」を右クリックし、ショートカット・メニューで「新規関数」を選択します。

  2. 「PL/SQLファンクション作成」ダイアログ・ボックスで、名前としてGET_JOBSと入力します。「OK」をクリックします。GET_JOBSファンクションの定義がソース・エディタに表示されます。

  3. ファンクション定義の最初の行で、VARCHAR2のかわりに、戻り値としてJobsPkg.ref_cursorを指定します。

  4. ASキーワードの後に、次のように入力します。

     jobs_cursor JobsPkg.ref_cursor;
    
  5. BEGINブロックで、次のコードを入力して現在の内容を置き換えます。

      OPEN jobs_cursor FOR
      SELECT job_id, job_title FROM jobs;
      RETURN jobs_cursor;
    
  6. ファンクションを保存します。

例6-11に、ファンクションのコードを示します。

例6-11 ストアド・ファンクションの作成

FUNCTION    "GET_JOBS"
RETURN JobsPkg.ref_cursor
AS jobs_cursor JobsPkg.ref_cursor;
BEGIN
  OPEN jobs_cursor FOR
  SELECT job_id, job_title FROM jobs;
  RETURN jobs_cursor;
END;

6.3.3.3 メソッドからのREF CURSORのコール

次の手順では、GET_JOBSファンクションをコールして結果セットを取得するJavaメソッドgetJobsDataHandlerクラスに作成します。

  1. DataHandler.javaがまだ開いていない場合は、ダブルクリックしてソース・エディタで開きます。

  2. メソッド宣言を入力します。

    public ResultSet getJobs() throws SQLException {
     
    }
    
  3. メソッド本体で、データベースに接続します。

      getDBConnection();
    
  4. 接続に続いて、新しい変数jobqueryを宣言します。

      String jobquery = "begin ? := get_jobs; end;";
    
  5. prepareCallメソッドを使用して、CallableStatementを作成します。

      CallableStatement callStmt = conn.prepareCall(jobquery);
    
  6. Oracle固有の型を使用して、OUTパラメータの型を登録します。

      callStmt.registerOutParameter(1, OracleTypes.CURSOR);
    
  7. Oracle固有の型を使用することを指定すると、[Alt]+[Enter]キーを押してoracle.jdbc.OracleTypesをインポートすることを求めるメッセージが表示されます。[Alt]+[Enter]キーを押した後、表示されるリストでOracleTypes(oracle.jdbc)を選択します。

  8. 文を実行して結果セットを返します。

      callStmt.execute();
      rset = (ResultSet)callStmt.getObject(1);
    
  9. ここまでに入力したコードをtryブロックで囲みます。

  10. 例外を捕捉するためのcatchブロックを追加し、logExceptionメソッドもコールします。

    catch ( SQLException ex ) {
      logException( ex );
    }
    
  11. catchブロックを閉じた後で、結果セットを返します。

    return rset;
    
  12. 構文エラーをチェックするためのファイルを作成します。

getJobsメソッドのコードを次に示します。

  public ResultSet getJobs() throws SQLException {
  try {
    getDBConnection();
    String jobquery = "begin ? := get_jobs; end;";
    CallableStatement callStmt = conn.prepareCall(jobquery);
    callStmt.registerOutParameter(1, OracleTypes.CURSOR);
    callStmt.execute();
    rset = (ResultSet)callStmt.getObject(1);
  } catch ( SQLException ex ) {
  logException( ex );
  }
  return rset;
  }

6.3.3.4 動的に生成されたリストの表示

職務IDと職務名のリストを挿入ページに表示するドロップ・ダウン・リストを作成するには、職務IDと職務名をハードコードします。次の手順では、これを前の項で作成したREF CURSORから提供される動的生成リストに置き換えます。

  1. insert.jspが開いていない場合は、アプリケーション・ナビゲータのビジュアル・エディタでダブルクリックして開きます。

  2. 「Page Directive」useBeanタグの右側のページにドラッグします。「Page Directiveの挿入」ダイアログ・ボックスで「言語」javaを入力し、「インポート」フィールドでjava.sql.ResultSetを参照して選択します。「OK」をクリックします。

  3. 「Page Directive」の隣のページにスクリプトレットをドラッグします。「スクリプトレットの挿入」ダイアログ・ボックスで、次のコードを追加し、getJobsメソッドを実行して、職務のリストを含む結果セットを返します。

    ResultSet rset = empsbean.getJobs();
    
  4. ページでListBoxコンポーネントを選択し、JSPのコンポーネント・パレットの「スクリプトレット」をクリックします。(この場合、スクリプトレットをページにドラッグ・アンド・ドロップする必要はありません。)「スクリプトレットの挿入」ダイアログ・ボックスが表示されます。

  5. 次のコードを「スクリプトレットの挿入」ダイアログ・ボックスに入力します。「OK」をクリックします。

      while (rset.next ())
       {
        out.println("<option value=" + rset.getString("job_id") + ">" + 
        rset.getString("job_title") + "</option> "  );
       }
    
  6. 次のように、ハードコードされた値を削除します。

    ListBoxコンポーネントが選択された状態のまま、「構造」ウィンドウで「ジョブ」フィールドにスクロールします。selectキーワードの下のハードコードされたオプションのリストを確認します。各オプションを削除しますが、スクリプトレットは保持されることを確認します。

    図6-3 ドロップダウン・リストボックス・オプションの構造の表示

    図6-3の説明が続きます。
    「図6-3 ドロップダウン・リストボックス・オプションの構造の表示」の説明

  7. ページを保存します。

ここで、アプリケーションを実行し、クリックして新しい従業員を挿入し、リストを使用して選択可能な職務のリストを表示します。図6-4に、ブラウザでの動的な職務のリストを示します。

図6-4 ブラウザで動的に生成されたリスト

図6-4の説明が続きます。
「図6-4 ブラウザで動的に生成されたリスト」の説明