JDBC を使用してデータを XML に抽出する

XML の時代にレガシー・データも簡単に使用することができます

データを保管するには XML が最も適していることから、いずれは、データベースから情報を引き出して、その情報を XML であるかの如く操作することを依頼される日がやって来るはずです。このチュートリアルでは、JDBC を使用してデータベースにアクセスし、SQL を使用して情報を抽出する方法、そして抽出したデータから所定のマッピングに従って XML 文書を作成する方法を説明します。

Nicholas Chase, Writer, Freelance

Photo of Nicholas ChaseNicolas Chase は、Lucent Technologies、Sun Microsystems、Oracle Corporation、Tampa Bay Buccaneers などの企業で Web サイト開発に携わってきました。Nick は高校の物理教師、低レベル放射性廃棄物施設のマネージャー、オンライン・サイエンス・フィクション雑誌の編集者、マルチメディア・エンジニア、そして Oracle インストラクターとしての経歴を積んできました。最近では、フロリダ州クリアウォーターにある Site Dynamics Interactive Communications で最高技術責任者としての役目も果たしています。また、『Java and XML From Scratch』(Que) をはじめとする 3 冊の Web 開発に関する書籍の著者です。



2012年 3月 01日

はじめに

このチュートリアルの対象読者

このチュートリアルの目的は、データベースから情報を抽出して XML 文書に組み込む必要に迫られている Java 開発者を支援することです。

このチュートリアルでは、読者に Java および XML 全般の知識と、特に DOM (Document Object Model) について十分な知識があることを前提とします。Java プログラミングに慣れている必要はありますが、チュートリアルで説明する手法をマスターするには、JDBC を使用したデータベース接続に関する事前の知識は必要ありません。チュートリアルでは、SQL の基礎を簡単に説明します。アプリケーションの入出力についてはコマンドラインから操作するので、GUI プログラミングの知識は不要です。「参考文献」セクションには XML および DOM の基礎に関するチュートリアルや、SQL に関する詳細な基礎知識を提供してくれるサイトへのリンクを記載してあります。

このチュートリアルの内容

データを保管するには XML が最も適していることから、いずれは、データベースから情報を引き出して、その情報を XML であるかの如く操作することを依頼される日がやって来るはずです。JDBC は、Java を使用してデータベースにアクセスする、ベンダーに依存しないデータベース接続方式です。このチュートリアルでは、JDBC ドライバーをインスタンス化し、そのインスタンスを使ってデータベースに接続して情報を取得する方法を説明します。また、SQL の基礎と、JDBC クエリーの作成方法とそのクエリーの実行結果の使用方法についても説明します。

このチュートリアルでは、データベースからデータを抽出して XML 文書を作成します。XML 文書の構造はマッピング・ファイルによって決定しますが、このマッピング・ファイルに XML ファイルを使用する一例を示します。

ツール

このチュートリアルは実際にサンプル・コードを実行しなくても、コードを読むだけでトピックとして取り上げた内容を理解するのに役立つはずです。チュートリアルを読むのと並行してサンプル・コードを実行する場合には、以下のツールがインストールされていて、正しく機能していることを確認してください。

  • テキスト・エディター: XML および Java ソース・ファイルは単なるテキストです。テキスト・エディターさえあれば、ファイルを作成したり、読んだりすることができます。
  • Java 環境: 例えば、http://java.sun.com/j2se/1.3/ から入手できる Java 2 SDK を使用してください。
  • Java APIs for XML Processing: これは、JAXP 1.1 としても知られる、Sun が提供しているリファレンス実装です。JAXP は、Java Web Services Developer Pack 1.1 のコンポーネントとしてダウンロードすることができます。
  • データベース: ODBC または JDBC ドライバーがインストールされていれば、SQL を実行できるデータベースです。JDBC ドライバーについては、http://industry.java.sun.com/products/jdbc/drivers に 150 を超えるドライバーのリストが検索可能な形で提供されています (ODBC ドライバーがインストールされている場合には、このステップを省略して、JBDC-ODBC ブリッジを使用することができます)。このチュートリアルで使用する JDataConnect は、http://www.jnetdirect.com/products.php?op=jdataconnect から入手することができます。

このチュートリアルで使用する表記規則

このチュートリアルでは、説明をわかりやすくするために、以下の表記規則を使用します。

  • 入力する必要のあるテキストについては、太字の等幅フォントにして鉤括弧でくくります。一部のサンプル・コードでは、テキストで参照しているタグや要素を太字にすることで見つけやすくします。
  • ウィンドウ名、ダイアログ・ボックス名、および機能名については、斜体フォントにして鉤括弧でくくることで明示します。
  • ファイル名およびパス名については、等幅フォントにして鉤括弧でくくります。
  • このチュートリアルでは一貫して、説明に関係しないコード・セグメントを省略し、省略記号 (...) で置き換えます。

JDBC を使用してデータベースにアクセスする

JDBC とは何か

チュートリアル「Using JDBC to insert XML data into a database」をすでにひと通り読んだ方は、「SELECT 文の構造」セクションまでスキップして構いません。

それほど昔の話ではありませんが、かつてデータベースを操作するためには、開発者がその特定のデータベースに固有の API を使用しなければなりませんでした。そのため、データベースに依存しないアプリケーションを作成するのは、不可能ではないとしても困難でした。

JDBC は、ODBC (Open Database Connectivity) と同様に、データベースへのアクセスを仲介する標準 API です。前述のとおり、標準 JDBC コマンドを使用すると、JDBC ドライバーがこれらのコマンドをデータベースに固有の API に変換します。

このチュートリアル全体を通して、特定のデータベースについては言及されていません。データベースの選択はほとんど関係してこないためです。すべてのコマンドは標準 JDBC コマンドであり、JDBC ドライバーによって特定のデータベースに固有のコマンドに変換されます。このある種の API 非依存性により、ドライバー名と、場合によっては接続を作成したときに使用した接続 URL を変更するだけで、アプリケーションで使用するデータベースを簡単に変えることができます。

使用しているデータベースに適切な JDBC ドライバーをダウンロードするには、「参考文献」セクションのリンクを参照してください。実質的にあらゆるデータベースに対応する、150 を超える JDBC ドライバーが用意されています。

さらには、対応する JDBC ドライバーがないデータベースのための方法もあります。

図 1. ネイティブ・ブリッジ・ドライバーを使用したデータベースとの接続例
ネイティブ・ブリッジ・ドライバーを使用したデータベースとの接続例

JDBC-ODBC ブリッジ

ODBC ドライバーを使用できる限り、データベースに固有の JDBC ドライバーを使用しなければならないわけではありません。代わりに、JDBC-ODBC ブリッジを使用できるからです。アプリケーションが JDBC-ODBC ブリッジを呼び出すと、このブリッジがコマンドを ODBC に変換し、それをさらに ODBC ドライバーがネイティブ API に変換します。

JDBC-ODBC ブリッジは、推奨されるデータベース・アクセス方法ではありません。それには、パフォーマンスと構成の両方に関するさまざまな理由があります。例えば、2 つの API を経由してコマンドを渡さなければならないこと、そしてすべてのクライアントに ODBC ドライバーをインストールして構成しなければならないことなどです。しかし、純粋な JDBC ドライバーを使用できない場合に、テストおよび開発目的で使用するには無難な選択となります。

ブリッジを使用することにした場合には、Windows システム上で「Start (スタート)」 > 「Settings (設定)」 > 「Control Panel (コントロール パネル)」 > 「Administrative Tools (管理ツール)」 > 「ODBC Data Sources (データ ソース (ODBC))」の順に選択し、「System DSN (システム DSN)」タブでシステム・データ・ソースを作成します。作成したシステム DSN については名前をメモしておいてください。接続を作成するときに、この名前を参照します。

図 2. JDBC-ODBC ブリッジを使用したデータベースとの接続例
JDBC-ODBC ブリッジを使用したデータベースとの接続例

データベースとドライバーをセットアップする

create table products (
   product_id   numeric primary key,
   product_name varchar(50),
   base_price   numeric,
   size         numeric,
   unit         varchar(10),
   lower        numeric,
   upper        numeric,
   unit_price   numeric )

まず始めに、使用することにしたデータベースがインストールされていて稼働中であること、そしてドライバーが使用可能であることを確認します。JDBC ドライバーは、http://industry.java.sun.com/products/jdbc/drivers からダウンロードすることができます。

データベースを作成した後は、必要なテーブルを作成します。このチュートリアルで使用するのは、products というテーブルだけです。このテーブルの構造は上記のとおりです。使用しているデータベースに適した手順に従ってテーブルを作成してください。

注: 通常、上記のデータは 2 つ以上の関連するテーブルに分割されますが、説明を単純にするため、この例では 1 つのテーブルだけでデータを表現します。

データベースにアクセスする際のプロセス

Java を使用してデータベースを操作するには、一般に以下の手順に従います。

  1. データベース・ドライバーをロードします。これは、JDBC ドライバーまたは JDBC-ODBC ブリッジのいずれかです。
  2. データベースとの Connection を作成します。
  3. Statement オブジェクトを作成します。これが、実際に SQL またはストアード・プロシージャーを実行するオブジェクトです。
  4. ResultSet を作成し、そこに、実行したクエリーの結果を取り込みます (データの取得、またはデータを直接更新することが目的の場合)。
  5. ResultSet のデータを取得または更新します。

java.sql パッケージには Java 2 SDK, Standard Edition ディストリビューションの一部として、データベースにアクセスするための JDBC 2.0 Core API が含まれています。さらに Java 2 SDK, Enterprise Edition の一部として配布される javax.sql パッケージには、JDBC 2.0 Optional Package API が含まれています。

このチュートリアルで使用するクラスは、すべて JDBC 2.0 Core API に含まれています。

ドライバーをインスタンス化する

データベースにアクセスするには、最初に JDBC ドライバーをロードします。そのときどきで、使用できるドライバーにはさまざまなものがあるはずですが、使用するドライバーを決定するのは DriverManager クラスです。このクラスは、既知のドライバーごとに接続の作成を試みて、最初に接続に成功したドライバーをアプリケーションで使用します。DriverManager がドライバーの存在を認識するには 2 通りの方法があります。

1 つ目の方法は、以下のサンプル・コードに示しているように、Class.forName() を使用して直接ドライバーをロードするという方法です。ドライバー・クラスがロードされると、DriverManager に登録されます。

public class Pricing extends Object {

   public static void main (String args[]){

      //For the JDBC-ODBC bridge, use
      //driverName = "sun.jdbc.odbc.JdbcOdbcDriver"
      String driverName = "JData2_0.sql.$Driver";

      try {
         Class.forName(driverName);
      } catch (ClassNotFoundException e) {
         System.out.println("Error creating class: "+e.getMessage());
      }
   }
}

ドライバーが正常にロードされれば、アプリケーションはデータベースに接続することができます。

DriverManager がドライバーの存在を突き止めるもう 1 つの方法は、sql.drivers システム・プロパティーに記述されているドライバーを順に調べることです。sql.drivers プロパティーには、使用可能なドライバーのリストがコロンで区切って含まれます。クラスが動的にロードされる前に、必ずこのリストがチェックされるため、特定のドライバーを使用する必要がある場合には、sql.drivers プロパティーが空であるか、あるいは目的のドライバーがリストの先頭にあることを確認してください。

接続を作成する

ドライバーのロードが完了すると、アプリケーションがデータベースに接続できるようになります。

DriverManager は、静的メソッド getConnection() を使用して接続を行います。このメソッドが取る引数は、データベースの URL です。データベースの URL は一般に以下のように参照されます。

jdbc:<sub-protocol>:databasename

参照 URL は、アクティブなドライバーが認識できる任意のフォーマットで書き込むこともできます。URL のフォーマットについては、使用している JDBC ドライバーのドキュメントを参照してください。

ODBC を介して接続する場合には、サブプロトコルが関与してきます。例えば、サンプル・データベースの DSN が pricing に設定されているとします。その場合、ODBC を介して直接データベースにアクセスするとしたら、URL は以下のようになります。

odbc:pricing

したがって、JDBC を介して接続する場合には、以下の URL になります。

jdbc:odbc:pricing

以下に、実際の接続を作成します。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class Pricing extends Object {

   public static void main (String args[]){

      //For the JDBC-ODBC bridge, use
      //driverName = "sun.jdbc.odbc.JdbcOdbcDriver"
      //and
      //connectURL = "jdbc:odbc:pricing"
      String driverName = "JData2_0.sql.$Driver";
      String connectURL = "jdbc:JDataConnect://127.0.0.1/pricing";
      Connection db = null;	   
      try {
         Class.forName(driverName);
         db = DriverManager.getConnection(connectURL);
      } catch (ClassNotFoundException e) {
         System.out.println("Error creating class: "+e.getMessage());
      } catch (SQLException e) {
         System.out.println("Error creating connection: "+e.getMessage());
      }
   }
}

接続に成功した後は、必要なデータベース操作 (例えば、データの挿入や更新など) を何でも実行することができます。

接続をクローズする

StatementConnection はオブジェクトであるため、Java はこれらのオブジェクトが占有するデータベース・リソースを解放するために、この 2 つをガーベッジ・コレクションの対象にします。したがって、これらのオブジェクトをクローズすることについては心配する必要がないと思うかもしれませんが、それは誤りです。

Java アプリケーション自体が使用できるリソースが大量にあり、ガーベッジ・コレクションが行われる頻度が少ないという事態は当然あり得ますが、Java アプリケーションに大量のリソースがあっても、使用可能なデータベース・リソースは限られているという事態も同じくあり得る話です。その場合、データベース・リソースの多くが、アプリケーションが簡単にクローズできたはずの Java オブジェクトによって使用されている可能性があります。

これらのオブジェクトは、エラーの有無とは関係なく、確実にクローズすることが重要です。そのためには、すでに配置されている try-catch ブロックに、finally ブロックを追加してください。

...
      Connection db = null;	  
      try {
         Class.forName(driverName);
         db = DriverManager.getConnection(connectURL);
      } catch (ClassNotFoundException e) {
         System.out.println("Error creating class: "+e.getMessage());
      } catch (SQLException e) {
         System.out.println("Error creating connection: "+e.getMessage());
      } finally {
         System.out.println("Closing connections...");
         try {
            db.close();
         } catch (SQLException e) {
            System.out.println("Can't close connection.");
         }
      }
   }
}

皮肉なことに、close() メソッド自体が SQLException をスローすることもあるため、このメソッド専用の try-catch が必要です。


JDBC を使用してデータベースから情報を抽出する

SELECT 文の構造

データベースに接続した後は、アプリケーションがデータ取得のプロセスを開始することができます。SQL では、データベースに保管されているデータを取得するには、(通常は) SELECT 文を使用します。SELECT 文には、いくつかの基本構成要素があります。例えば、以下の例を見てください。

SELECT product_id, product_name FROM products WHERE product_id < 1000 ORDER BY product_id

上記の文は、以下のように分解することができます。

  • SELECT product_id, product_name: SELECT 節は、テーブル (またはテーブルのグループ) から取得する列を定義します。すべての列を取得するには、SELECT * を使用します。
  • FROM products: FROM 節は、どのテーブルに格納されているデータを取得するかを定義します。複数のテーブルからデータを取得することもできます。これは、結合と呼ばれる方法で、結合を使用する場合には、慎重に作成された WHERE 節が必要になります。
  • WHERE product_id < 1000: WHERE 節によって、有効な行のうち、どの行が返されるかが決まります。
  • ORDER BY product_id: ORDER BY 節によって、データが返される順序が決まります。

SELECT 文では、行をグループにまとめて、集約した値を返すこともできます。例えば、以下の文によって返される値は、2001年 9月 15日に $1000 を超える収益を上げた製品すべての収益を合計した値です。

SELECT product_id, sum(quantity*price) as revenue FROM orders WHERE order_date = '9/15/01' GROUP BY product_id HAVING revenue > 1000

SELECT 文を実行するのは、Statement オブジェクトです。

Statement オブジェクトを作成する

Statement オブジェクトを作成するには、ConnectioncreateStatement() メソッドを使用した上で、SQLException が発生した場合にその例外を確実に捕捉できるようにすればよいのです。このセクションで使用するクラスのほとんどは SQLException をスローするため、コードの残りは try-catch ブロックに記述されます。

...
import java.sql.Statement;

public class Pricing extends Object {
...
      } catch (SQLException e) {
         System.out.println("Error creating connection: "+e.getMessage());
      }
	  
	  //Create the Statement object, used to execute the SQL statement
      Statement statement = null;
      try {
         statement = db.createStatement();
      } catch (SQLException e) {
         System.out.println("SQL Error: "+e.getMessage());
      }   finally {
         System.out.println("Closing connections...");
         try {
            db.close();
         } catch (SQLException e) {
            System.out.println("Can't close connection.");
         }
      }
   }
}

PreparedStatement を作成する場合も、CallableStatement でストアード・プロシージャーを呼び出す場合も、同様の仕組みとなります。

Statement オブジェクトを実行する

実際にデータを取得するためには、Statement を実行しなければなりません。それには通常、以下のように ResultSet として返されるデータ・セットを作成するための SELECT 文を渡す必要があります。

...
import java.sql.ResultSet;

public class Pricing extends Object {
...
      //Create the Statement object, used to execute the SQL statement
      Statement statement = null;
      //Create the ResultSet object, which ultimately holds the data retrieved
     ResultSet resultset = null;
      try {
         statement = db.createStatement();
         //Execute the query to populate the ResultSet
         resultset = statement.executeQuery("SELECT * FROM products");
      } catch (SQLException e) {
         System.out.println("SQL Error: "+e.getMessage());
      }	 finally {
...

SQL 文に問題があると (例えば、存在しないテーブルを参照しているなど)、アプリケーションは SQLException をスローします。問題がなければ、データが見つかったかどうかに関係なく、アプリケーションが処理を続けます。


データに対してテストを実行する

図 3. データ・セットでの ResultSet ポインターの位置
データ・セットでの ResultSet ポインターの位置

作成される ResultSet には、データ・セット内での相対位置を参照する「ポインター」があります。ResultSet が返された文が実行された直後には、(たとえテーブルが空の場合でも) このポインターは最初の行のすぐ「上」に位置します。

アプリケーションが実際のデータの先頭行に移動するためには、next() メソッドを呼び出します。このメソッドが返すのは、新しい位置に行が存在するかどうかを示すブール値です。データが見つからない場合、next()false を返します。

...
         resultset = statement.executeQuery("select * from products");	
         
         //Check for data by moving the cursor to the first record (if there is one)
         if (resultset.next()) {
            System.out.println("Data exists.");
         } else {
            System.out.println("No data exists.");
         }
      } catch (SQLException e) {
...

後でデータをループ処理する際には、これと同様の手法を使用します。

データ型

データの存在が確定した後は、ResultSetgetXXX() メソッドを使用してデータを取得することができます。getXXX() という名前のメソッドは実際にはありませんが、ResultSet が返す可能性のあるデータの型はさまざまなので、このような名前の一連のメソッドがあります。例えば、データベース内に格納されている一式のデータが整数だとすると、ResultSet はそのデータを数値 (getDouble()getInt()getFloat() などのメソッドを使用した場合)、String (getString() を使用した場合)、あるいは配列 (getArray() を使用した場合) としてアプリケーションに返すことが考えられます。大量のデータの場合には、InputStream (getBinaryStream() を使用した場合) または Reader (getCharacterStream() を使用した場合) として返されることもあります。

重要な点として、Java はほとんどのデータベースに見られるようなデータ型に厳密に適合できること、そしてその型以外の型として取得できるのは特定のデータ型に限られることを覚えておいてください。例えば、getString() は、データベースに最初に保管された時点でのデータ型によらずにデータを取得することができますが、日付と時刻の値を取得するには getDate() (または getTime())、getObject()、あるいは getString() しか使用することができません。

名前を基準にデータを取得する

データ自体を取得するには 2 つの方法があります。1 つは名前を基準に取得する方法、もう 1 つはインデックスを基準に取得する方法です。名前を基準に取得する場合には、前述の getXXX() メソッドのいずれかを使用します。これらのメソッドは、int または String 形式の引数を取ります。インデックスを基準にデータを取得する方法については追って詳しく説明するとして、とりあえず、このアプリケーションでは列名を基準にフィールドを取得することにします。

最終的には、以下のすべてのデータが XML ファイルに格納されます。XML ファイルではすべてのデータがテキストであるため、値を取得するには例外なく getString() を使用します。

...
         if (resultset.next()) {
            //Output data by referencing the ResultSet columns by name
            System.out.print(resultset.getString("product_id")+"|");
            System.out.print(resultset.getString("product_name")+" | ");
            System.out.print(resultset.getString("base_price")+" | ");
            System.out.print(resultset.getString("size")+" | ");
            System.out.print(resultset.getString("unit")+" | ");
            System.out.print(resultset.getString("lower")+" | ");
            System.out.print(resultset.getString("upper")+" | ");
            System.out.println(resultset.getString("unit_price"));
         } else {
            System.out.println("No data exists.");	 
         }
...

アプリケーションをコンパイルして実行すると、先頭行のデータが表示されます。これは、オンライン高級食材販売業者が販売している食材の大量注文価格の情報です。

図 4. 名前を基準にデータを取得する (先頭行のデータ)
名前を基準にデータを取得する (先頭行のデータ)

データをループ処理する

データを一度に 1 行ずつ表示する方法も役には立ちますが、データをループ処理して行ごとに各レコードを表示できればさらに便利です。

このように表示するためには、アプリケーションが次の行に進んでデータを出力し、続いて次の行に進んでデータを出力するという処理を繰り返す必要があります。ポインターが最後の行を過ぎた時点で、next()false を返し、ループが終了します。

...
         resultset = statement.executeQuery("select * from products");	
         //Execute the loop as long as there is a next record
         while (resultset.next()) {
            //Output data by referencing the ResultSet columns by name
            System.out.print(resultset.getString("product_id")+" | ");
            System.out.print(resultset.getString("product_name")+" | ");
            System.out.print(resultset.getString("base_price")+" | ");
            System.out.print(resultset.getString("size")+" | ");
            System.out.print(resultset.getString("unit")+" | ");
            System.out.print(resultset.getString("lower")+" | ");
            System.out.print(resultset.getString("upper")+" | ");
            System.out.println(resultset.getString("unit_price"));
         }
      } catch (SQLException e) {
...

このアプリケーションを実行すると、テーブル内のすべての行が返されます。

図 5. データのループ処理によるテーブル内のすべての行の表示
データのループ処理によるテーブル内のすべての行の表示

インデックスを基準にデータを取得する

データを列名で取得する操作は、当然のことながら、かなり厄介な作業になる可能性があります。これは、多数の列が関係してくる場合には尚更のことです。また、列名を使ってデータを取得するとなると、その操作を一般化するのも、カスタマイズするのも難しくなります。データを取得するまでの時間を短縮するとともに、より簡単にカスタマイズできるようにするには、各列のインデックス番号を使用します。

インデックスは、最初の列には 1 が付けられ、2 番目の列には 2 が付けられるといった具合に付けられていきます。8 列あることがわかっていれば、前のサンプル・コードは以下のように書き換えることができます。

...
         while (resultset.next()) {
           for (int i=1; i <= 8; i++) {
               //Output each column by its index
               System.out.print(resultset.getString(i)+" | ");
            }
               //Output a line feed at the end of the row
               System.out.println("");
            }
...
図 6. インデックスを基準にデータを取得する例
インデックスを基準にデータを取得する例

上記の手法を使用すれば、データを取得するプロセスが完全に一般化されるため、他の同様のタスクやアプリケーションにも、このプロセスを移植できるようになります。

汎用的な取得操作

このチュートリアルの最終的な目標は、アプリケーションにはまったく依存せずに、マッピング・ファイルをベースとしたデータの取得および操作手続きを作成することです。したがって、アプリケーションはデータがどのように構造化されているか事前にわかっていなくても、データを取得できるようでなければなりません。つまり、このアプリケーションに必要なのは、ResultSet に含まれる列の数を独力で突き止める方法です。

そのために使用するのは、ResultSetMetaData クラスです。データベースのメタデータと同じように、このクラスからは、列の数と各列の型だけでなく、列の名前やその他の情報にアクセスすることができます。

ResultSetMetaData を使用すると、レコードに関するすべての情報を出力することができます。それはレコードに ResultSet 自体の情報しか含まれていない場合であっても同じです。

...
import java.sql.ResultSetMetaData;

public class Pricing extends Object {

...
      Statement statement = null;
      ResultSet resultset = null;
      //Create the ResultSetMetaData object, which will hold information about
      //the ResultSet
      ResultSetMetaData resultmetadata = null;
      try {
         statement = db.createStatement();
         resultset = statement.executeQuery("select * from products");	
		 
         //Get the ResultSet information
         resultmetadata = resultset.getMetaData();
         //Determine the number of columns in the ResultSet
         int numCols = resultmetadata.getColumnCount();
		 
         while (resultset.next()) {
            for (int i=1; i <= numCols; i++) {
               //For each column index, determine the column name
String colName = resultmetadata.getColumnName(i);
               //Get the column value
String colVal = resultset.getString(i);
               //Output the name and value
System.out.println(colName+"="+colVal);
            }
            //Output a line feed at the end of the row
            System.out.println(" ");
         }
...

アプリケーションを実行すると、今度はデータだけでなく、列名も表示されます。これらの列名は、データに対応する XML 文書を作成する際に必要になります。

図 7. 汎用的なデータ取得操作の例
汎用的なデータ取得操作の例

ResultSet のオプション

これまでは、アプリケーションで使用していた ResultSet はデフォルト・プロパティーで作成されていましたが、これらのプロパティーを調整することによって、データを取得する方向や、他のユーザーが行った変更を ResultSet で表示するかどうかなどを制御することができます。

例えば、ResultSet をスクロールしたり、ResultSet を使ってデータを直接更新したりすることができるように、ResultSet を作成することができます。この場合、ResultSet は上から下の順にデータを取得し、他のデータベース・ユーザーによる変更には影響されません。

これらのプロパティーは、実際には、最終的に ResultSet を作成する Statement に設定されます。

Statement statement = db.createStatement(
                                         ResultSet.TYPE_SCROLL_INSENSITIVE,
                                         ResultSet.FETCH_FORWARD
                                         );

ResultSet の作成メソッドにカスタム・プロパティーをいくつも渡すと、アプリケーションのパフォーマンスに影響する可能性があることに注意してください。

PreparedStatement

アプリケーションのパフォーマンスを向上させる 1 つの方法は、PreparedStatement を使用することです。

PreparedStatement は、SQL 文をパラメーターとして使用して作成されるという点を除き、Statement と同様です。ほとんどの場合、SQL 文はデータベースによってプリコンパイル (または、少なくともキャッシュ) されることになります。アプリケーションが以下のように構造化されているとしたら、SELECT 文がプリコンパイルされます。

...
import java.sql.PreparedStatement;

public class Pricing extends Object {
...	  
      //Create the PreparedStatement
      PreparedStatement statement = null;
      ResultSet resultset = null;
      ResultSetMetaData resultmetadata = null;
      try {

         //Compile or cache the SQL within the database and prepare it for execution
         statement = db.prepareStatement("select * from products");
         //Execute the SQL above to populate the ResultSet
         resultset = statement.executeQuery();	
	  
         //Get the ResultSet Information
         resultmetadata = resultset.getMetaData();
...

PreparedStatement がとりわけ役立つのは、特定のクエリーを繰り返し実行する場合でしょう。その場合、パラメーターを実行時に設定できると便利です。

IN パラメーターを設定する

StatementPreparedStatement を再利用するほとんどの場合において、レコードの範囲が異なるなど、その都度多少の違いがあるものです。そのような場合に必要となるのが、IN パラメーターです。例えば、実行時に決定される product_id の範囲を取得するには、以下のようにします。

...
 statement = db.prepareStatement("select * from products where "+
                                 "product_id < ? and product_id > ?");
statement.setInt(1, 5);
 statement.setInt(2, 10);
		 
 resultset = statement.executeQuery();	
...

値を設定する setXXX() メソッドは、値を取得する getXXX() メソッドに対応するメソッドですが、パラメーター番号とそのパラメーターに設定する値を含めるという点が異なります。例えば、setInt(2, 10) は、文の 2 番目の ? を整数 10 で置き換えます。したがって、この文は、以下のように作成されているかのように実行されます。

select * from products where product_id < 5 and product_id > 10

CallableStatement でストアード・プロシージャーを呼び出すときにも、これと同様の手法を適用することができます。

CallableStatement でストアード・プロシージャーを呼び出す

最近のほとんどのデータベースでは、開発者がデータベース内にストアード・プロシージャーを作成できるようになっています。作成するストアード・プロシージャーは単純な単一の SQL 文にすることも、複雑なミニアプリケーションにすることもできます。いずれにしても、取得するデータ・セットを生成するために、Java からこれらのプロシージャーを呼び出さなければならない場合があります。

PreparedStatement を継承する CallableStatement クラスでは、開発者がデータベース・クエリーに対してパラメーターを指定することができます。その場合、CallableStatement はそのパラメーターに応じて ResultSet (または複数の ResultSet) を返します。

CallableStatement を作成する方法は、PreparedStatement を作成する方法とほとんど同じで、SQL 文の代わりに call 文を使用するという点が異なるだけです。call 文は、ドライバーによってネイティブ呼び出しに変換されます。

statement = db.prepareCall("{call product_listing }");

注:CallableStatementPreparedStatement の違いの 1 つは、CallableStatement は通常作成される ResultSet だけでなく、OUT パラメーターも提供できることです。

NULL 値を検出する

このチュートリアルで取り上げているデータは、品物の大量注文価格に関連します。そのため、場合によっては量の範囲の上限が、それ以上の数量割引がないことを意味する NULL となることもあります。

上限が NULL になることは仕方ありませんが、それによって、最終的な XML を組み立てるのが難しくなります。XML では、空の値が問題の原因となることがあるためです。この問題を解決するには、wasNull() メソッドを使用してデータの特定の部分が NULL であるかどうか、そして NULL を何か別の値で置換するかどうかを判別するという方法を使えます。以下のサンプル・コードでは、NULL 値を「and up」という単語で置き換えています。

...
         while (resultset.next()) {
            //Output each row
            for (int i=1; i <= numCols; i++) {
               //For each column, get name and value information
               String colName = resultmetadata.getColumnName(i);
               String colVal = resultset.getString(i);
               //Determine if the last column accessed was null
if (resultset.wasNull()) {
                  colVal = "and up";
               }
               //Output the information
               System.out.println(colName+"="+colVal);
            }
            System.out.println(" ");
         }
...

wasNull() に引数がないことに注意してください。このメソッドは、ResultSet から取得された最後の列に作用するため、先に getXXX() の呼び出しを行う必要があります。

図 8. NULL 値を検出する例
NULL 値を検出する例

以上の作業で、アプリケーションが適切なデータと列名を取得するようになりました。これで、XML 文書の作成に取り掛かれます。


マッピングをセットアップする

マッピングが機能する仕組み

このチュートリアルの目標は、マッピング・ファイルを使用して、データベースに保管されているデータから XML 文書を作成する方法を説明することです。つまり、どのデータを取得するか、そしてそのデータを最終的に XML ファイルでどう表現するかは、マッピング・ファイルによって決まります。

その 1 つの方法は、データベースから抽出したデータで一時的な XML 文書を作成した上で、マッピング・ファイルに従ってデータを新しいフォーマットに変換する方法です。マッピング・ファイルによって、抽出するデータ、新規ファイルの名前と構造、そしてデータの保管場所が決定されます。

構造

マッピング・ファイルには、以下の情報を含めます。

  • 元のデータ (data 要素の形式): 最大限の柔軟性を引き出すために、データは SQL 文という形にします。このようにすれば、マッピング・ファイルを使用して、データが複数のテーブルから抽出されるように指定することができます。
  • 新規文書の全体的な構造 (root 要素の形式): root 要素では、宛先ルート要素の名前と、データベース行を表す要素の名前を、属性によって指定します。
  • data 要素の名前と内容: これらの情報を一連の element 要素の中に含めます。element 要素に含められるのは、新規要素の名前を表す name 属性と、すべての attribute 要素または content 要素です。これら 2 つの要素は、それぞれ、content 要素は追加するデータを指定し、attribute 要素は追加するデータの名前を指定します。例えば、description 要素に product_id 列を表す product_number 属性と、この要素の内容として product_name を指定する必要がある場合には、マッピング・ファイルはこれらの情報を以下のように表現します。
    <element name="description">
        <attribute name="product_number">product_id</attribute>
        <content>product_name</content>
    </element>

マッピング・ファイル

以下に、最終的なマッピング・ファイルを記載します。

<?xml version="1.0"?>
<mapping>
   <data sql="select * from products" />
   <root name="pricingInfo" rowName="product">
      <element name="description">
          <attribute name="product_number">product_id</attribute>
          <content>product_name</content>
      </element>
      <element name="quantity">
          <content>lower</content>
      </element>
      <element name="size">
          <content>size</content>
      </element>
      <element name="sizeUnit">
          <content>unit</content>
      </element>
      <element name="quantityPrice">
          <content>unit_price</content>
      </element>
   </root>
</mapping>

SQL の実行結果を使用して XML 文書を作成する

アルゴリズム

新規 XML 文書を作成するプロセスは以下のとおりです。

  1. マッピング・ファイルを構文解析します。これにより、どのデータを取得するかをはじめ、必要な情報が得られます。
  2. ソース・クエリーを取得します。これにより、マッピング・ファイルに基づいてデータを動的に取得できるようになります。
  3. データを Document オブジェクトに格納します。その後、この一時文書からデータを抽出し、マッピングに従って目的の文書を作成することになります。
  4. データ・マッピングを取得します。これにより、アプリケーションでデータ・マッピングを使用できるようになります。
  5. 元のデータをループ処理します。ループ処理により、データの各行が分析されて新しい構造に再マッピングされます。
  6. 要素マッピングを取得します。このマッピング・ファイルによって、一時文書から抽出するデータとその順序が決まります。
  7. 新規文書に要素を追加します。取得したデータを新しい名前で新規文書に追加します。
  8. 新規文書に属性を追加します。最後に、あらゆる属性を適切な要素に追加します。

マッピング・ファイルを構文解析する

新規文書を作成する最初のステップは、マッピング情報を取得することです。その唯一の方法は、マッピング・ファイルを構文解析することです。マッピング・ファイルには最終的に取得するデータへの参照も含まれているため、マッピング・ファイルを構文解析してからでないと、一切のデータベース操作を実行することができません。

...
import org.w3c.dom.Document;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class Pricing extends Object {

  public static void main (String args[]){

    //Create the Document object   
    Document mapDoc = null;
    try {
      //Create the DocumentBuilderFactory
      DocumentBuilderFactory dbfactory = 
               DocumentBuilderFactory.newInstance();
      //Create the DocumentBuilder
      DocumentBuilder docbuilder = dbfactory.newDocumentBuilder();
      //Parse the file to create the Document
      mapDoc = docbuilder.parse("mapping.xml");
    } catch (Exception e) {
      System.out.println("Problem creating document: "+e.getMessage());
    }

    //For the JDBC-ODBC bridge, use
    //driverName = "sun.jdbc.odbc.JdbcOdbcDriver"
    //and
    //connectURL = "jdbc:odbc:pricing"
    String driverName = "JData2_0.sql.$Driver";
    String connectURL = "jdbc:JDataConnect://127.0.0.1/pricing";
    Connection db = null;
...

ソース・クエリーを取得する

続いて、data 要素の sql 属性に格納されているソース・クエリーを取得します。

...
import org.w3c.dom.Element;
import org.w3c.dom.Node;
...
         System.out.println("Problem creating document: "+e.getMessage());
      }

      //Retrieve the root element 
      Element mapRoot = mapDoc.getDocumentElement();
        //Retrieve the (only) data element and cast it to Element
        Node dataNode = mapRoot.getElementsByTagName("data").item(0);
        Element dataElement = (Element)dataNode;
        //Retrieve the sql statement
        String sql = dataElement.getAttribute("sql");

        //Output the SQL statement
        System.out.println(sql);

      //For the JDBC-ODBC bridge, use
      //driverName = "sun.jdbc.odbc.JdbcOdbcDriver"
      //and
      //connectURL = "jdbc:odbc:pricing"
      String driverName = "JData2_0.sql.$Driver";
      String connectURL = "jdbc:JDataConnect://127.0.0.1/pricing";
      Connection db = null;
...

最初にルート要素を判別し、続いて data ノードを取得します。data 要素は 1 つしかないので、直接取得することができます。連続して実行される複数のクエリーから文書を作成する場合にも、同様の手法を使用することができます。

最後に NodeElement にキャストして、Attribute 値を使用できるようにします。

以前の出力文を削除した上でアプリケーションを実行すると、SQL 文が出力として表示されます。

図 9. 出力としての SQL 文
出力としての SQL 文

データを Document オブジェクトに格納する

データベースから正常に抽出されたデータは、一時 Document に格納します。その一般的な方法としては、データの行ごとに対応する row 要素を作成し、各列をその列にちなんだ名前を付けた要素として表します。そしてデータ自体をその要素の内容として表します。

...
   public static void main (String args[]){

      Document mapDoc = null;
      //Define a new Document object
      Document dataDoc = null;
      try {
         //Create the DocumentBuilderFactory
         DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
         //Create the DocumentBuilder
         DocumentBuilder docbuilder = dbfactory.newDocumentBuilder();
         //Parse the file to create the Document
         mapDoc = docbuilder.parse("mapping.xml");

         //Instantiate a new Document object
         dataDoc = docbuilder.newDocument();
      } catch (Exception e) {
         System.out.println("Problem creating document: "+e.getMessage());
      }
...
      ResultSetMetaData resultmetadata = null;
 
      //Create a new element called "data"	  
      Element dataRoot = dataDoc.createElement("data");

      try {
         statement = db.createStatement();
         resultset = statement.executeQuery("select * from products");	

         resultmetadata = resultset.getMetaData();
         int numCols = resultmetadata.getColumnCount();

         while (resultset.next()) {
            //For each row of data
            //Create a new element called "row"
            Element rowEl = dataDoc.createElement("row"); 

            for (int i=1; i <= numCols; i++) {
               //For each column, retrieve the name and data
               String colName = resultmetadata.getColumnName(i);
               String colVal = resultset.getString(i);
               //If there was no data, add "and up"
               if (resultset.wasNull()) {
                  colVal = "and up";
               }
               //Create a new element with the same name as the column
               Element dataEl = dataDoc.createElement(colName);
               //Add the data to the new element
               dataEl.appendChild(dataDoc.createTextNode(colVal));
               //Add the new element to the row
               rowEl.appendChild(dataEl);
            }

            //Add the row to the root element			
            dataRoot.appendChild(rowEl);

         }

      } catch (SQLException e) {
         System.out.println("SQL Error: "+e.getMessage());
      }	 finally {
         System.out.println("Closing connections...");
         try {
            db.close();
         } catch (SQLException e) {
            System.out.println("Can't close connection.");
         }
      }

      //Add the root element to the document
      dataDoc.appendChild(dataRoot);
   }
}

上記のサンプル・コードを具体的に説明すると、このコードは最初にルート要素である data と併せて空の文書を作成します。次に、データベース内の行ごとに row 要素を作成し、列ごとに個々の要素を作成して row 要素に追加します。そして最後に、各 row 要素をルート要素に追加した上で、ルート要素を Document に追加します。

データ・マッピングを取得する

データの用意ができたら、次はデータを新しい構造にマッピングします。構文解析されたマップ文書からマッピング情報を取得するために、まずルート要素と row 要素に関する情報を取得し、続いて要素のマッピング自体を取得します。

...
import org.w3c.dom.NodeList;
...
      dataDoc.appendChild(dataRoot);

      //Retrieve the root element (also called "root")
      Element newRootInfo = 
               (Element)mapRoot.getElementsByTagName("root").item(0);
      //Retrieve the root and row information
      String newRootName = newRootInfo.getAttribute("name");
      String newRowName = newRootInfo.getAttribute("rowName");
      //Retrieve information on elements to be built in the new document
      NodeList newNodesMap = mapRoot.getElementsByTagName("element");

   }
}

この情報があれば、新規 Document を作成することができます。

元のデータをループ処理する

元の行は、一時文書にそれぞれ row 要素として格納されています。これらの要素をループ処理して、要素を NodeList として取得する必要があります。

...
      NodeList newNodesMap = mapRoot.getElementsByTagName("element");

      //Retrieve all rows in the old document
      NodeList oldRows = dataRoot.getElementsByTagName("row");
      for (int i=0; i < oldRows.getLength(); i++){

         //Retrieve each row in turn
         Element thisRow = (Element)oldRows.item(i);

      }  
...

要素マッピングを取得する

データとマッピング情報が用意できたところで、新規 Document の作成を開始します。行ごとにマップを繰り返し処理して、一時 Document からデータ列を取得する順序、そしてデータ列を新規 Document に追加する際に付ける名前を決定します。

...
    for (int i=0; i < oldRows.getLength(); i++){

      //Retrieve each row in turn	   
      Element thisRow = (Element)oldRows.item(i);

    for (int j=0; j < newNodesMap.getLength(); j++) {

        //For each node in the new mapping, retrieve the information
        //First the new information...  
        Element thisElement = (Element)newNodesMap.item(j); 
        String newElementName = thisElement.getAttribute("name");	

        //Then the old information
        Element oldElement = 
               (Element)thisElement.getElementsByTagName("content").item(0);
        String oldField = oldElement.getFirstChild().getNodeValue();

      } 

    }  
...

newNodesMap に含まれる各要素について、アプリケーションは取得対象の新しい要素名を取得し、続いてその要素の元の名前を取得します。

新規文書に要素を追加する

新規要素を文書に追加するには、適切な名前の新規要素を作成し、その要素の内容として該当するデータを取得して設定するだけです。

...
   public static void main (String args[]){

      Document mapDoc = null;
      Document dataDoc = null;
      //Create the new Document
      Document newDoc = null;
      try {
         //Create the DocumentBuilderFactory
         DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
         //Create the DocumentBuilder
         DocumentBuilder docbuilder = dbfactory.newDocumentBuilder();
         //Parse the file to create the Document
         mapDoc = docbuilder.parse("mapping.xml");
         //Instantiate a new Document object
         dataDoc = docbuilder.newDocument();

         //Instantiate the new Document
         newDoc = docbuilder.newDocument();
      } catch (Exception e) {
         System.out.println("Problem creating document: "+e.getMessage());
      }

...	  
      //Retrieve the root element (also called "root")
      Element newRootInfo = (Element)mapRoot.getElementsByTagName("root").item(0);
      //Retrieve the root and row information
      String newRootName = newRootInfo.getAttribute("name");
      String newRowName = newRootInfo.getAttribute("rowName");
      //Retrieve information on elements to be built in the new document
      NodeList newNodesMap = mapRoot.getElementsByTagName("element");

      //Create the final root element with the name from the mapping file
      Element newRootElement = newDoc.createElement(newRootName);

      NodeList oldRows = dataRoot.getElementsByTagName("row");
      for (int i=0; i < oldRows.getLength(); i++){

         //For each of the original rows	   
         Element thisRow = (Element)oldRows.item(i);

         //Create the new row
         Element newRow = newDoc.createElement(newRowName);
         			   
         for (int j=0; j < newNodesMap.getLength(); j++) {
			   
            //Get the mapping information for each column
            Element thisElement = (Element)newNodesMap.item(j); 
            String newElementName = thisElement.getAttribute("name");	

            Element oldElement = 
               (Element)thisElement.getElementsByTagName("content").item(0);
            String oldField = oldElement.getFirstChild().getNodeValue();

            //Get the original values based on the mapping information
            Element oldValueElement = 
               (Element)thisRow.getElementsByTagName(oldField).item(0);
            String oldValue = 
               oldValueElement.getFirstChild().getNodeValue();

            //Create the new element
            Element newElement = newDoc.createElement(newElementName);
            newElement.appendChild(newDoc.createTextNode(oldValue));
            //Add the new element to the new row
            newRow.appendChild(newElement);

         }
         //Add the new row to the root
         newRootElement.appendChild(newRow);
      }
      //Add the new root to the document
      newDoc.appendChild(newRootElement);
   }
}

まず、新規 Document を作成し、次に新規ルート要素を作成します。この要素の名前は、マッピング情報から取得されます。一時 Document に含まれる行ごとに、マップに指定された newRowName を使用して新しい行に対応する要素を作成します。

行ごとに、マッピングに指定された新しい要素のそれぞれをループ処理し、元のデータを取得します。前のサンプル・コードでは content 要素のテキストを順に取得しました。この情報を使用して、一時行から取得するノードと、その順序を決定します。元のデータと新しい名前を取得した後、新規要素を作成して行に追加します。

最後に、新しい行をルートに追加した上で、ルートを Document に追加します。これで、他に追加しなければならないのは属性だけとなりました。

新規文書に属性を追加する

新規 Document の完成まで、あと一歩です。新しい要素は追加しましたが、要素内で指定されている可能性のある属性はまだ追加していません。属性を追加する方法は、新規要素を追加する方法と同様ですが、1 つの要素に複数の属性が存在する可能性があるので、コードではその点を考慮する必要があります。複数の属性に対処する最も簡単な方法は、attribute 要素を NodeList に取り込んでから、このリストを繰り返し処理して各属性を処理することです。必要な属性ごとに、元の Document でのフィールド名と、新規 Document でのフィールド名を判別します。

...
       Element newElement = newDoc.createElement(newElementName);
       newElement.appendChild(newDoc.createTextNode(oldValue));

       //Retrieve list of new elements
        NodeList newAttributes = 
               thisElement.getElementsByTagName("attribute");
        for (int k=0; k < newAttributes.getLength(); k++) {
           //For each new attribute
           //Get the mapping information
           Element thisAttribute = (Element)newAttributes.item(k);
           String oldAttributeField = 
               thisAttribute.getFirstChild().getNodeValue();
           String newAttributeName = thisAttribute.getAttribute("name");

           //Get the original value
           oldValueElement = 
               (Element)thisRow.getElementsByTagName(oldAttributeField).item(0);
           String oldAttributeValue = 
               oldValueElement.getFirstChild().getNodeValue();
		
           //Create the new attribute		
           newElement.setAttribute(newAttributeName, oldAttributeValue);
          }
        //Add the element to the new row
        newRow.appendChild(newElement);
      }
      //Add the new row to the root
      newRootElement.appendChild(newRow);
...

最終的な文書

以上のプロセスが終了した時点で、newDoc には古い情報が新しいフォーマットで格納されます。完成した新規文書は、別のアプリケーションで使用することも、XSLT やその他の手段でさらに変換することもできます。

<pricingInfo>
   <product>
      <description product_number="1">Filet Mignon</description>
      <quantity>1</quantity>
      <size>1</size>
      <sizeUnit>item</sizeUnit>
      <quantityPrice>40</quantityPrice>
   </product>
   <product>
      <description product_number="2">Filet Mignon</description>
      <quantity>11</quantity>
      <size>1</size>
      <sizeUnit>item</sizeUnit>
      <quantityPrice>30</quantityPrice>
   </product>
   <product>
      <description product_number="3">Filet Mignon</description>
      <quantity>101</quantity>
      <size>1</size>
      <sizeUnit>item</sizeUnit>
      <quantityPrice>20</quantityPrice>
   </product>
   <product>
      <description product_number="4">Prime Rib</description>
      <quantity>1</quantity>
      <size>1</size>
      <sizeUnit>lb</sizeUnit>
      <quantityPrice>20</quantityPrice>
   </product>
   <product>
      <description product_number="5">Prime Rib</description>
      <quantity>101</quantity>
      <size>1</size>
      <sizeUnit>lb</sizeUnit>
      <quantityPrice>15</quantityPrice>
   </product>
...

JDBC によるデータ抽出手法のまとめ

まとめ

このチュートリアルでは、JDBC によってデータベースに接続してデータを取得し、そのデータを使用して XML ファイルを作成する方法を詳細に検討しました。また、アプリケーションを汎用的なものにして、あらゆるクエリーや構造で使用できるようにする方法についても説明しました。これを実現する手段としてはメタデータも使用しました。

最終的な XML ファイルの構造は、XML マッピング・ファイルによって決定しました。このチュートリアルでは、マッピング・ファイルを読み込んで、一時 XML ファイルを目的の構造に変換する方法についても詳しく解説しました。


ダウンロード

内容ファイル名サイズ
Sample code for tutorialextractcodefiles.zip10KB

参考文献

学ぶために

  • JDBC を使用して XML 文書のデータをデータベースに挿入する方法については、関連するチュートリアルの「Using JDBC to insert XML data into a database」を読んでください。
  • XML の基礎知識については、チュートリアル「Introduction to XML」を一読してください。
  • DOM (Document Object Model) については、チュートリアル「Understanding DOM」を読んでください。
  • XML プログラミングの基礎を学ぶには、Doug Tidwell 氏の「XML programming in Java technology」を読んでください。
  • XML and Java from Scratch』(Nicholas Chase 著) を読んでください。JDBC の使用方法について、この記事以上に詳しく説明しているわけではありませんが、XML と Java の一般的な使用方法を説明しています。また、XML が持つその他のデータ中心の観点 (XML クエリーなど) や、XML の他の使用法 (SOAP など) についても説明しています。しかもこれは、この優れたチュートリアルの著者による著書です。
  • Sun の JDBC に関する Sun Microsystems 情報を参照してください。
  • 2001年7月に登場した最新の JDBC について、「What's new in JDBC 3.0」(Josh Heidebrecht 著) で調べてください。
  • An easy JDBC wrapper」(Greg Travis 著) を読んでください。
  • Java Enablement with DB2」サマリー・ページで、DB2 および JDBC の操作に関するアドバイスを入手してください。
  • developerWorks の Technical events and webcasts で最新情報を入手してください。

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

  • このチュートリアルに記載したサンプル・コードの zip アーカイブをダウンロードしてください。
  • Java 2 SDK, Standard Edition バージョン 1.3.1 をダウンロードしてください。
  • Java Web Services Developer Pack 1.1 をダウンロードして JAXP (Java APIs for XML Processing) 1.1 を入手してください。
  • お使いのデータベースに対応した JDBC ドライバーをダウンロードしてください。
  • JDataConnect をダウンロードしてください。この JDBC ドライバーは、DB2、Oracle、Microsoft SQL Server、Access、FoxPro、Informix、Sybase、Ingres、dBase、Interbase、Pervasive 他をサポートします。
  • オープンソースのデータベースをお望みの場合は、MySQLMySQL JDBC ドライバーをダウンロードしてください。
  • 次期開発プロジェクトの構築に、developerWorks から直接ダウンロードできる IBM の試用版ソフトウェアをご利用ください。

議論するために

コメント

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=XML
ArticleID=795540
ArticleTitle=JDBC を使用してデータを XML に抽出する
publish-date=03012012