名前付きパラメーターを使って CallableStatement を処理する

Informix Dynamic Server の新機能

IBM® Informix® Dynamic Server (IDS) の強力な新機能、「CallableStatement 内の名前付きパラメーター」について学んでください。パラメーターを順番で識別する代わりに、名前で識別することを可能にするこの機能は、CallableStatement の適用可能な範囲を広げ、順番によってもパラメーター名によっても CallableStatement を使用できるようにします。この記事では、パラメーターを識別するこの 2 つの手法の違いを説明し、パラメーターを順番で指定する代わりに名前付きパラメーターを使用した場合の利点を探ります。

Akhilesh K. Tiwary (aktiwary@in.ibm.com), Staff Software Engineer, Informix CSDK Lead, IBM

Akhilesh Tiwary photoAkhilesh Kumar Tiwary は、インドの IBM Software Labs で CSDK チームのリーダーとして JDBC に取り組んでいます。



Thamizhchelvan A. Anbalagan (tanbalag@in.ibm.com), System Software Engineer, Development Engineer, IBM

T. AnbalaganTamil は、インドの IBM Software Labs で IBM Informix JDBC チームの開発エンジニアとして活躍しています。これまで 3 年間、IDS の JDBC および OAT (Open Admin Tool) に取り組んでいます。



2008年 2月 21日

はじめに: JDBC でのステートメント処理

JDBC アプリケーションでは、SQL 文をデータベース・サーバーに送信するために JDBC ステートメント・オブジェクトを使用します。ステートメント・オブジェクトは接続に関連付けられているため、ステートメント・オブジェクトが、アプリケーションとデータベース・サーバーとの通信を処理します。

JDBC で使用できるステートメント・オブジェクトには、次の 3 つのタイプがあります。

  1. 一般ステートメント
  2. 準備済みステートメント
  3. 呼び出し可能ステートメント

ステートメント・オブジェクトは接続と関連付けられます。したがって、ステートメント・オブジェクトを作成するには、データベース接続を確立しなければなりません。

接続の作成方法

リスト 1 のサンプル・コードで接続を作成する方法を説明します。

リスト 1. Informix ドライバーをロードして接続を作成する場合のサンプル・コード
Connection con = null;
try {
Class.forName("com.informix.jdbc.IfxDriver");				
	String url = "jdbc:informix-sqli://hostname:port_number/dbname:
informixserver=servername; userid=userid;password=pwd;";
con = DriverManager.getConnection(url);		
}

それでは早速、3 つのタイプのステートメント・オブジェクトについて、それぞれ 1 つひとつ順番に検討していきます。


一般ステートメント

一般ステートメントは、接続の createStatement メソッドを使用して作成されます。このステートメントは、パラメーターとして値を渡す必要のない SQL 文専用です。

リスト 2. create 文のサンプル・コード
Statement stmt = con.createStatement();
      cmd = "create database testDB;";
      rc = stmt.executeUpdate(cmd);
stmt.close();

準備済みステートメント

準備済みステートメントは、ステートメント・クラスのサブクラスです。ステートメント・クラスとの主な違いは、準備済みステートメントは一度コンパイルされて最適化されると、後は異なるパラメーター値を設定することで繰り返し使用できるという点です。したがって、ステートメントを複数回実行する必要がある場合には、準備済みステートメントを使用するのが適しています。このステートメントはコンパイル済みの形式なので、実行時間が短縮されます。つまり、準備済みステートメントには SQL 文だけでなく、プリコンパイルされた SQL 文も含められるという利点があります。また、ステートメント・クラスとのもう 1 つの違いとして、SQL 文は作成されるとすぐに準備済みステートメントに渡されるという点も挙げられます。

リスト 3. 準備済みステートメントのサンプル・コード
PreparedStatement pstmt = con.prepareStatement("UPDATE tab1 "+
                    "set col1 = ? where key = 1");
pstmt.setShort(1, (short)2);
int rowcount = pstmt.executeUpdate();

上記の準備済みステートメントは、col1 の別の値セットにも使用することができます。パラメーターがいったん設定されると、準備済みステートメントは、パラメーターがリセットされるか、または clearParameters が呼び出されるまで、そのパラメーターの値を維持します。この機能のおかげで、準備済みステートメントをバッチ INSERT/UPDATE に使用することが可能になっています。

バッチ更新

バッチ更新は、さまざまな値を設定して繰り返し実行される 1 つのステートメントのパフォーマンスを向上させる機能です。この機能を使うと、複数の更新操作をデータ・ソースに実行依頼して一度で処理することができます。バッチ更新はステートメント・オブジェクトにも使用することができます。ステートメント・オブジェクトはバッチ処理の対象であるさまざまな SQL 文を送信するだけに過ぎませんが、準備済みステートメントはパラメーターのセットを送信してバッチ処理を行います。

リスト 4 に、準備済みステートメントでバッチ挿入を使う方法を示します。

リスト 4. バッチ更新のサンプル・コード
PreparedStatement pst = conn.prepareStatement("insert into tab1 values (?)");
for loop....
{
	pst.setInt (1, i);
	pst.addBatch();
}
pst.executeBatch();

addBatch メソッドはステートメントをキャッシュに追加し、キャッシュに入れられたステートメントを executeBatch() メソッドを使ってデータベースにフラッシュします。ステートメントは (準備済みステートメントにより) 一度しかコンパイルされないため、コンパイル/最適化の時間が短縮されます。それと同時に、バッチ挿入は一度に送信されるのでサーバーまでの往復の時間も省くことができます。


呼び出し可能ステートメント

SQL 文を呼び出す 3 つ目の方法である呼び出し可能ステートメントでは、Java™ プログラムからサーバー上のストアード・プロシージャーを呼び出すことができます。呼び出し可能ステートメントもまずコンパイルする必要があります。その上で、設定メソッドによってパラメーターを設定することになりますが、パラメーター値を設定するには以下のいずれかの方法を使用することができます。

  1. パラメーター順
  2. 名前付きパラメーター

パラメーター順は、パラメーターを CallableStatement 内での順番で識別して設定するという従来からのパラメーター設定方法です。一方、名前付きパラメーターでは、順番の代わりに名前を使ってパラメーターを識別するので、柔軟な設定をすることができます。CallableStatement のパラメーターは、ルーチンの呼び出しごとに、パラメーターの名前あるいは順番のいずれかのフォーマットを使用して指定しなければなりません。例えば 1 つの引数に対してパラメーターの名前を指定した場合は、引数のすべてでパラメーター名を使用する必要があります。

名前付きパラメーターが特に役立つのは、引数が多数あり、そのうちの一部にはデフォルト値が設定されたストアード・プロシージャーを呼び出す場合です。ストアード・プロシージャーが固有のものであれば、デフォルト値を持つパラメーターは省略し、その他のパラメーターを任意の順番で入力することができます。つまり、名前付きパラメーターを使用すると、ストアード・プロシージャー内のパラメーターの順番が変わったとしてもアプリケーションを変更しなくてもいいため、アプリケーションが堅牢になります。

JDBC ドライバーには、JDBC ドライバーと RDMS が CallableStatement 内の名前付きパラメーターをサポートするかどうかを判断する DatabaseMetaData.supportsNamedParameters() メソッドが用意されています。名前付きパラメーターがサポートされる場合は、システムが true を返します。以下は、その一例です。

リスト 5. supportsNamedParameters() の使用法
Connection myConn = . . .   // connection to the RDBMS for Database
      DatabaseMetaData dbmd = myConn.getMetaData();
      if (dbmd.supportsNamedParameters() == true)
      {
          System.out.println("NAMED PARAMETERS FOR CALLABLE"
                            + "STATEMENTS IS SUPPORTED");
      }

ストアード・プロシージャーのパラメーター名を取得する方法

ストアード・プロシージャーのパラメーター名を取得するには、DatabaseMetaDatagetprocedureColumns をリスト 6 のように使用します。

リスト 6. getProcedureColumn() メソッドの使用法
Connection myConn = . . .   // connection to the RDBMS for Database
 . .
      DatabaseMetaData dbmd = myConn.getMetaData();
      ResultSet rs = dbmd.getProcedureColumns(
       "myDB", schemaPattern, procedureNamePattern, columnNamePattern);
      rs.next() {
          String parameterName = rs.getString(4);
 - - - or - - -
 String parameterName = rs.getString("COLUMN_NAME"); 
 - - -
          System.out.println("Column Name: " + parameterName);

上記によって、getProcedureColumns() メソッドのパラメーターと一致するすべての列名が表示されます。

リスト 7 に、CallableStatement で名前付きパラメーターを使用する方法を示します。

ストアード・プロシージャーの作成

リスト 7. 呼び出し可能な OUT パラメーターの使用法
create procedure createProductDef(productname   varchar(64),
                 productdesc  varchar(64),
                 listprice    float,
                 minprice     float,
             out prod_id      float);
. . .
  let prod_id="value for prod_id";
end procedure;

リスト 8 に示す Java コードは、まず、ストアード・プロシージャーに対応する 5 個のパラメーターを持つ CallableStatement を作成します。これらのパラメーターを参照するのは、JDBC 呼び出しに含まれる括弧内の疑問符 (?) です。すべてのパラメーターを設定、または登録してください。パラメーターに名前を付けるには、cstmt.setString("arg", name); というフォーマットを使用します。ここで、arg は対応するストアード・プロシージャーに含まれる引数の名前を示します。パラメーターに名前を付ける順番は、ストアード・プロシージャー内の引数と同じ順番にする必要はありません。

リスト 8. 呼び出し可能な名前付きパラメーターの使用法
String sqlCall = "{call CreateProductDef(?,?,?,?,?)}";
      CallableStatement cstmt = conn.prepareCall(sqlCall);

      cstmt.setString("productname", name);     // Set Product Name.
      cstmt.setString("productdesc", desc);     // Set Product Description.
      cstmt.setFloat("listprice", listprice);   // Set Product ListPrice.
      cstmt.setFloat("minprice", minprice);     // Set Product MinPrice.

      // Register out parameter which should return the product is created.

      cstmt.registerOutParameter("prod_id", Types.FLOAT);

      // Execute the call.
      cstmt.execute();

      // Get the value of the id from the OUT parameter: prod_id
      float id = cstmt.getFloat("prod_id");

CallableStatement に含まれるパラメーターの数がストアード・プロシージャー内の引数の数より少ない場合は、残りの引数の値にはデフォルト値を設定してください。デフォルト値を持つ引数には、サーバーが自動的にそのデフォルト値を使用するため、値を設定する必要はありません。例えば、ストアード・プロシージャーに 10 個の引数があり、そのうちの 4 個はデフォルト値以外の値を持ち、残りの 6 個はデフォルト値を持つとします。この場合、CallableStatement には少なくとも 4 個の疑問符が必要となります。あるいは疑問符を 5 個あるいは 6 個にするなど、最大 10 個の疑問符を使用することができます。以下の固有のストアード・プロシージャーでは、listprice 引数と minprice 引数にデフォルト値を設定しています。

リスト 9. 引数にデフォルト値を設定したプロシージャーの作成
create procedure createProductDef(productname   varchar(64),
                 productdesc  varchar(64),
                 listprice    float default 100.00,
                 minprice     float default  90.00,
             out prod_id      float);
. . .
  let prod_id = value for prod_id;
end procedure;

リスト 10 は、ストアード・プロシージャーの引数よりパラメーターの数が少ないストアード・プロシージャーを呼び出す Java コードです (5 つの引数に対して 4 つのパラメーターしかありません)。listprice にはデフォルト値が設定されているため、CallableStatement から省略することができます。

リスト 10. デフォルト・パラメーターの使用法
String sqlCall = "{call CreateProductDef(?,?,?,?)}";
                                              // 4 params for 5 args
      CallableStatement cstmt = conn.prepareCall(sqlCall);

      cstmt.setString("productname", name);   // Set Product Name.
      cstmt.setString("productdesc", desc);   // Set Product Description.
    
      cstmt.setFloat("minprice", minprice);   // Set Product MinPrice.

      // Register out parameter which should return the product id created.

      cstmt.registerOutParameter("prod_id", Types.FLOAT);

      // Execute the call.
      cstmt.execute();

      // Get the value of the id from the OUT parameter: prod_id
      float id = cstmt.getFloat("prod_id");

呼び出し可能ステートメントに OUT または INOUT パラメーターが含まれている場合には、これらのパラメーターを CallableStatementregisterOutParameter を使用して登録してください。リスト 11 では、out パラメーター prod_id を使って、OUT パラメーターを持つストアード・プロシージャーを作成しています。INOUT パラメーターの場合も同様に、キーワード INOUT を使用して作成することができます。

リスト 11. INOUT および OUT パラメーターの使用法
create procedure createProductDef(productname   varchar(64),
                 productdesc  varchar(64),
             inout    listprice    float default 100.00,
                 minprice     float default  90.00,
             out prod_id      float);

リスト 12 では、CallableStatement の registerOutparameter メソッドを使用して CallableStatement の out パラメーターを登録しています。

リスト 12. CallableStatement への OUT パラメーターの登録
cstmt.registerOutParameter("prod_id", Types.FLOAT);

リスト 13 は、すべてのステートメントを名前付きパラメーターの機能を使用して 1 つにまとめたものです。

リスト 13. 名前付きパラメーター機能のデモをするためのプログラム
package Callable;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
public class out1 {
    static Connection conn;	
    public static void main(String[] args) {
        getConnect();
        System.out.println("Connection Established");
        createProc();
        runthis();
        System.out.println("\n=============Finished=============");
        System.exit(0);
    }
    private static void getConnect() {
        try
        {
            Class.forName("com.informix.jdbc.IfxDriver");
            String url = "jdbc:informix-sqli://host name or ip :porn number/database
                 name:informixserver=dbservername;";
            System.out.println("URL: "+url);
            conn = DriverManager.getConnection(url);
            }
        catch( Exception e )
        {
            e.printStackTrace();
            System.exit(1);
        }
    }
    private static void createProc() {
        String str=null;
        Statement stmt = null;
        try 
        {
            stmt = conn.createStatement();
        } 
        catch (SQLException e2) 
        {
            e2.printStackTrace();
        }
        str="drop function c_out_proc";
        try 
        {
            stmt.executeUpdate (str);
        } 
        catch (SQLException e1) 
        {	}
        str = "create function  c_out_proc ( i int, OUT d varchar(20) ) \n" +
        "returning float; \n" +
        "define f float; \n" +
        "let d= \"Hello OUT\"; \n" +
        "let f=i*2; \n" +
        "return f; \n" + 
        "end function; \n";
        try
        {
            stmt.executeUpdate (str);
            System.out.println("Function created \n");
        }
        catch (SQLException e)
        {
            System.out.println("Error on creating function: " + e.toString());
            System.exit(1);
        }		
    }
    private static void runthis() 
    {
        CallableStatement cstmt = null;
        String command = "{? = call c_out_proc(?, ?)}  ";
        try 
        {
            cstmt = conn.prepareCall (command);
            cstmt.setInt(1, 2);
            cstmt.registerOutParameter(2, Types.VARCHAR);
            ResultSet rs = cstmt.executeQuery();
            if (rs == null)
            {
                System.out.println("rs is null *** this is BAD.");
                System.exit(0);
            }
            else
            {
                rs.next();
                System.out.println(rs.getFloat(1));
                System.out.println(cstmt.getString(2));
            }
        } 
        catch (SQLException e) 
        {
            e.printStackTrace();
        }
    }
}

まとめ

この記事では、まず始めに IDS JDBC ドライバーで使用できるさまざまなステートメントのタイプを紹介し、続いて名前付きパラメーターの機能を説明するとともに、CallableStatement での名前付きパラメーターの使用方法を取り上げました。

記事の締めくくりとして、IDS 11 サーバーで名前付きパラメーター機能を使用するデモ・プログラムを掲載しています。このプログラムを使って、名前付きパラメーターの利点を自分で試し、確かめてみてください。

参考文献

学ぶために

製品や技術を入手するために

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Information Management, Java technology
ArticleID=295310
ArticleTitle=名前付きパラメーターを使って CallableStatement を処理する
publish-date=02212008