【2/17】今年は「濃厚」技術トーク!@ITメールセミナー スラッシュドット    はてなブックマーク  Yahoo!ブックマークに登録  印刷



新人SEのためのJava講座

Javaデータアクセスの基礎

佐藤直生
日本オラクル
2001/7/11

本記事は2001年に執筆されたものです。JDBC全般の最新情報は@IT Java Solutuionのカテゴリ「DB連携」をご参照ください。

第2回 JDBCによるDBへの接続と検索の実行

この連載では、Javaのデータベース・アクセスAPIである「JDBC」の機能を、サンプルコードを交えて解説していきます。また、J2EEにおけるJDBCの位置付けや、JDBCを利用するさまざまなテクノロジについても解説していく予定です。前提知識としては、Javaとリレーショナル・データベースに関するベーシックな知識があれば十分です。


今回の内容
簡単なJDBCアプリケーション
サンプルコード実行のための環境構築
JDBCドライバのロードとデータベース接続の確立
データ型のマッピング
JDBCでの検索処理


 
前回は、JDBCの概要とそのアーキテクチャについて解説しました。今回は、さっそくJDBCを使った簡単なサンプルアプリケーションを紹介しながら、JDBCによるデータベース接続と、データ型のマッピング、検索処理について解説します。


■簡単なJDBCアプリケーション

 それでは、簡単なJDBCアプリケーションのコードを見てみましょう。これは、同じマシンで動作しているOracle8iデータベースにユーザー名“SCOTT”で接続し、EMP表に対して問い合わせを実行し、その結果を標準出力に出力します。

// Javaデータアクセスの基礎 サンプルコード(1)
// EMP表への問合せを実行するJavaアプリケーション

// JDBC APIをインポート
import java.sql.*;class JavaDataAccess01 {
  public static void main (String args[])
  throws SQLException, ClassNotFoundException {

    // Oracle JDBC Driverのロード
    Class.forName("oracle.jdbc.driver.OracleDriver");
    // Oracle8iに接続
    Connection conn =
    DriverManager.getConnection
    ("jdbc:oracle:thin:@localhost:1521:ORCL", "scott", "tiger");

    // ステートメントを作成
    Statement stmt = conn.createStatement();

    // 問合せの実行
    ResultSet rset = stmt.executeQuery("select EMPNO, ENAME from EMP");

    // 問合せ結果の表示
    while ( rset.next() ) {
      // 列番号による指定
      System.out.println(rset.getInt(1) + "\t" + rset.getString(2));
           }

    // 結果セットをクローズ
    rset.close();

    // ステートメントをクローズ
    stmt.close();

    // 接続をクローズ
    conn.close();
  }
}
リスト JavaDataAccess01.java

 そして、このコードの実行結果は、次のようになります。

C:\JDBC>java JavaDataAccess01
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER


■サンプルコード実行のための環境構築

 ここで、本連載で紹介していくサンプルコードを実行するための環境を構築しておきましょう。サンプルコードの実行のためには、J2SEおよびデータベースを利用できる環境を準備する必要があります。本連載では、データベースにOracle8iを使用します。Oracle8iが用意できない方は、サイトからトライアル版をダウンロードして使用してください。

 CLASSPATHに、Oracle JDBC Driverのファイルclasses12.zipを追加しておきましょう。このファイルは、次の位置にあります。

<ORACLE_HOME>\jdbc\lib\classes12.zip

<ORACLE_HOME>は、Oracle8iをインストールしたホーム・ディレクトリ

 サンプルコードでは、データベースのSID、リスナの構成などにデフォルトの値を使用しているので、環境に合わせて変更しましょう。また、データベースの動作するマシンに合わせて、ホスト名も変更しましょう。

 また、SCOTTスキーマが作成されていない場合や再作成したい場合には、次のSQLスクリプトを実行しましょう。

<ORACLE_HOME>\RDBMS\ADMIN\utlsampl.sql

 なお、本連載では、サンプルコードの実行結果やファイル・パス表記として、Windows NTのものを使いますが、UNIXプラットフォームでも、当然実行可能です(WORAですね!)。

 Oracle8i以外でも、JDBC 2.0 API対応のJDBCドライバを持つデータベースであれば、サンプルコードを多少修正するだけで実行可能になるので、ぜひチャレンジしてみてください。


■JDBCドライバのロードとデータベース接続の確立

 では、サンプルコードをもう一度見てみましょう。JDBCドライバのロードとデータベースの接続をどう行っているかを見ていきます。

// Oracle JDBC Driverのロード
Class.forName("oracle.jdbc.driver.OracleDriver");

 まず、現行のクラス・ローダを使って、JDBCドライバのクラスをロードします。ここでは、Oracle JDBC Driverのクラスoracle.jdbc.driver.OracleDriverを指定しています。

// Oracle8iに接続
Connection conn =
  DriverManager.getConnection
    ("jdbc:oracle:thin:@localhost:1521:ORCL", "scott", "tiger");

 次に、java.sql.DriverManagerクラスのgetConnection()メソッドを用いて、データベースへ接続します。getConnection()メソッドの第1パラメータは、接続先のデータベース情報を表しており、「データベースURL」と呼ばれます。第2、第3パラメータには、それぞれデータベース・ユーザーとそのパスワードを指定します。

 データベースURLは、次のフォーマットで指定します。

jdbc:<サブプロトコル>:<サブネーム>

 Oracle JDBC Driverのサブプロトコルは、サンプルコードを見れば分かるようにoracleです。ところで、JDBC-ODBCブリッジ・ドライバのサブプロトコルは、odbcです。このように、それぞれのJDBCドライバは固有のサブプロトコルを持っています。

 サブネーム部分の構文は、JDBCドライバが独自に定義できるためドライバによって異なります。

 例えば、JDBC-ODBCブリッジ・ドライバの場合には、次のように、ODBCデータ・ソース名を指定します(“xyz”は、ODBCデータ・ソース名)。

jdbc:odbc:xyz

 Oracle JDBC Thin Driverの場合には、次のようなフォーマットとなります。

jdbc:oracle:thin:@<ホスト名>:<リスナのポート番号>:<Oracle SID>

 詳細は、使用するJDBCドライバのドキュメントを参考にしてください。


■データ型のマッピング

 ここで、SQLのデータ型とJavaのデータ型の間のマッピングについて、簡単に見ておきましょう。

 JDBCを利用して、データベースからデータを取得する場合、SQLデータ型で表現されているデータを、特定のJavaデータ型で表現する必要があります。逆に、データベース内のデータを更新する場合、Javaデータ型で表現されているデータを、特定のSQLデータ型のデータとして扱う必要があります。

 JDBCでは、SQL-92で定義されている標準的なSQLデータ型を、JDBCデータ型として定義しています。そして、このJDBCデータ型とJavaデータ型の間のデフォルト・マッピングも定義しています。このマッピングを表1に示します。

 これらの標準的なSQLデータ型に加えて、独自に定義したSQLデータ型を使用しているデータベースは、少なくありません。例えば、Oracle8iでは、254バイト以下の可変長文字列を表すデータ型 “VARCHAR”を拡張して、4000バイト以下の可変長文字列を表すデータ型 “VARCHAR2” を定義しています。

 データベース独自のSQLデータ型とJDBCデータ型の間のマッピングは、JDBCドライバが暗黙的に行います。そのため、Java開発者は、データベース独自のSQLデータ型を利用するデータベースにアクセスする場合でも、Javaデータ型とJDBCデータ型だけを考慮するだけでよくなるわけです。

 Oracle JDBC Driverで定義されている、Oracle8i SQLデータ型とJDBCデータ型の間のデフォルト・マッピングも、表1に合わせて示します。

 利用可能なSQLデータ型と対応するJavaデータ型の詳細は、使用するデータベース、およびJDBCドライバのドキュメントを参考にしてください。

  表1
Javaデータ型 JDBCデータ型 Oracle8i SQLデータ型
String CHAR CHAR
String VARCHAR VARCHAR2
String LONGVARCHAR LONG
java.math.BigDecimal NUMERIC NUMBER
java.math.BigDecimal DECIMAL NUMBER
boolean BIT NUMBER
byte TINYINT NUMBER
short SMALLINT NUMBER
int INTEGER NUMBER
long BIGINT NUMBER
float REAL NUMBER
double FLOAT NUMBER
double DOUBLE NUMBER
byte[] BINARY RAW
byte[] VARBINARY RAW
byte[] LONGVARBINARY LONGRAW
java.sql.Date DATE DATE
java.sql.Time TIME DATE
javal.sql.Timestamp TIMESTAMP DATE



■JDBCでの検索処理

 ここで再び、サンプルコードに戻りましょう。JDBCでの検索処理の部分を見ていきます。

// ステートメントを作成
Statement stmt = conn.createStatement();

 データベース接続を表すjava.sql.ConnectionオブジェクトのcreateStatement()メソッドを用いて、SQL文を表すjava.sql.Statementオブジェクトを作成します。

// 問合せの実行
ResultSet rset = stmt.executeQuery("select EMPNO, ENAME from EMP");

 問い合わせ(SELECT文)を実行する場合には、java.sql.StatementオブジェクトのexecuteQuery()メソッドを使用します。パラメータとして、SELECT文を指定します。このメソッドの戻り値は、問い合わせの結果セットを表すjava.sql.ResultSetオブジェクトになります。

// 問合せ結果の表示
while ( rset.next() ) {
  // 列番号による指定
  System.out.println(rset.getInt(1) + "\t" + rset.getString(2));
   }

 結果セットは、問い合わせ結果の複数行を表しています。結果セットでは、処理対象の行を表すためにカーソルを用います。カーソルは、結果セット作成直後は1行目の前に位置しています。next()メソッドにより、カーソルを1行ずつ下に移動して、問い合わせ結果を1行ずつ処理していきます。カーソルが最終行を超えると、next()メソッドがfalseを返すため、サンプルコードのように、whileループを利用すれば、結果セットのすべての行を処理できます。

図1 結果セットとカーソルのイメージ

 カーソルのある処理対象行のデータを取り出すためには、getXXX()メソッドを用います。SQLデータ型がNUMBER(4)、つまり4けたの整数であるEMP表のEMPNO列に対して、getInt()メソッドを用いています。また、SQLデータ型がVARCHAR2(10)であるEMP表のENAME列に対しては、getString()メソッドを用いています。マッピング・テーブルを見直してみれば、これらが、SQLデータ型に対応するデフォルトのJavaデータ型のgetXXX()メソッドになっていることが分かるでしょう。マッピング・テーブルは、サンのサイト(http://java.sun.com/docs/books/tutorial/jdbc/basics/retrieving.html)の表を参考にしてください。

 デフォルト・マッピングのJavaデータ型以外のデータ型でデータを取り出すことも可能ですが、特に理由がなければ、デフォルトのデータ型で取り出しましょう。

 getXXX()メソッドで列を指定するには、2つの方法があります。(1から始まる)列番号を用いて指定することもできるし、あるいは、列名を用いて以下のように指定することも可能です。

  System.out.println(rset.getInt("EMPNO") + "\t" +
rset.getString("ENAME"));  

 “select * from EMP” のように、列名を指定しないSELECT文の場合には、列番号を用いる方がコーディングが簡単になります。

 これらのオブジェクトは、ガベージ・コレクションされる際に、自動的にクローズされ、データベースやJDBCのリソースを解放します。ですが、以下のリストのように、オブジェクトが不要になった時点で、明示的にクローズしリソースを直ちに解放する、という習慣を身に付けておく方がいいでしょう。

// 結果セットをクローズ
rset.close();


// ステートメントをクローズ
stmt.close();

// 接続をクローズ
conn.close();

 第3回は、JDBCによる更新処理を取り上げる予定です。

■参考リファレンス

Java Solution FAQ(@IT)

J2EEの基礎(@IT)

JDBC APIドキュメント(Sun)

JDBC Data Access API(Sun、英語)

OTN Japan - Java(日本オラクル)

OTN - Java (米オラクル、英語)


 次回、「Javaデータアクセスの基礎」の掲載は7月下旬頃になります

連載記事一覧

 

ホワイトペーパーTechTargetジャパン

Java Solution フォーラム 新着記事

@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

RSSフィード

スキルアップ/キャリアアップ(JOB@IT)

- PR -
- PR -

お勧め求人情報

キャリアアップ 〜JOB@IT
@IT Special -PR-
  企業の仮想化に足りない“発想”とは?
仮想化運用管理のキモは意外なところに!

New!
  操作もマニュアルも分かりやすい!
ユーザー視点で開発されたPC管理ツール

New!
  仮想化すればコストは削減できるか?
仮想化に必要な「3つの視点」を解説する

  セキュリティを知り尽くす上野氏が登壇!
@ITメールソリューションLive! in Tokyo

  運用管理の課題を“2つの観点”から分析
ユーザー満足度の高い「仮想環境」とは?

  世界に通用するストレージの作り方とは?
製品に込めた思いを富士通の開発者に聞く

  OSSで手間も時間も、障害も減った――
「マピオンの事例」オープンソース活用法

  「ノートPCの持ち出し禁止」で大丈夫?
情報漏えいを防ぐ管理手法とインフラは?

  1日の処理を1秒に――MySQLの達人が語る
「コスト削減」できるチューニング

  ドキュメント作成を自動化して、SEの作業
効率を大幅アップ! Visio 2007の魅力

  急速に広がるHyper-Vでのサーバ仮想化
そのベストプラクティスをデルが解説

  @IT主催セミナーで語られた、「担当者に
求められるセキュリティ対策」をレポート

  @IT「Windows 7」 特設サイトオープン!
最新情報・移行ノウハウを公開しています