データの取得(SELECT)

広告

データベース接続が出来ましたので、データベースへSQL文を発行してデータを取得してみます。

SQL文を発行して結果を表示するには次の手順を行います。

SQL文を実行し結果を取得するためのステートメントを作成する
データベースへ問い合わせを実行する
データベースからの結果を取得する
リソースを開放する

では順を追って確認していきます。

ステートメントを作成する

ステートメントは問い合わせを実行したり、問い合わせの結果の取得に関するベースになるものです。ステートメントは「java.sql.Statement」インターフェースのオブジェクトですが、作成するにはコネクションから作成します。具体的には「Connection」インターフェースで定義されている"createStatement"メソッドを使います。

SQL 文をデータベースに送るための Statement オブジェクトを生成します。パ
ラメータなしの SQL 文は通常、Statement オブジェクトを使用して実行されま
す。同じ SQL 文が多数回実行される場合は、PreparedStatement オブジェクト
を使用する方が効率的です。 

返される Statement オブジェクトを使って作成された結果セットは、デフォル
トでは、TYPE_FORWARD_ONLY の型で、CONCUR_READ_ONLY の並行処理レベルを持
ちます。 

戻り値:
  新しいデフォルト Statement オブジェクト 
例外: 
  SQLException - データベースアクセスエラーが発生した場合

実際の使い方は次のようになります。

Connection conn = null;

try {
  conn = DriverManager.getConnection(url, user, password);

  Statement stmt = conn.createStatement();
}catch (SQLException e){
  out.println("SQLException:" + e.getMessage());
}

問い合わせの実行

ステートメントを作成したらSQL文を作成しデータベースに問い合わせを行います。問い合わせを実行するには「Statement」インターフェースで用意されている"executeQuery"メソッドを使います。

単一の ResultSet オブジェクトを返す、指定された SQL 文を実行します。

パラメータ:
  sql - データベースに送られる SQL 文。通常静的 SQL SELECT 文 
戻り値:
  指定されたクエリーによって作成されたデータを含む ResultSet オブジェ
    クト。null にはならない 
例外: 
  SQLException - データベースアクセスエラーが発生した場合、または指定さ
    れた SQL 文が単一の ResultSet オブジェクト以外のものを生成する場合

引数にはデータベースに送りたいSQL文が書かれた文字列を指定します。"executeQuery"メソッドを実行した結果、データベースから何らかの結果が帰ってくる場合には「ResultSet」インターフェースのオブジェクトとして取得できます。

実際の使い方は次のようになります。

Connection conn = null;

try {
  conn = DriverManager.getConnection(url, user, password);

  Statement stmt = conn.createStatement();
  String sql = "SELECT * FROM kabukatable";
  ResultSet rs = stmt.executeQuery(sql);
}catch (SQLException e){
  out.println("SQLException:" + e.getMessage());
}

結果の取得

SELECTなどのSQL文をデータベースへ送ると結果として複数の行を取得できます。取得した行などの情報は「ResultSet」インターフェースのオブジェクトに格納されていますので、このオブジェクトから実際の値を取得していきます。

「ResultSet」インターフェースのオブジェクトにはカーソルという概念があります。「ResultSet」オブジェクトには複数の行が含まれていますが、カーソルは「ResultSetオブジェクト」の中での現在の行の位置を表します。

最初はカーソルは先頭の行の1つ前にあります。その為、「ResultSet」から何か値を取り出そうとすると、まずカーソルを1つ進めて最初の行の位置にカーソルとを持って行きます。それからデータを取り出すと、「ResultSet」内にある最初の行のデータを取り出せます。次の行のデータを取り出す場合にはカーソルを再度1つ進めて次の行位置にまで持っていってから改めてデータを取り出すことになります。

カーソルを動かすには「ResultSet」インターフェースで定義されている"next"メソッドを使います。

カーソルを現在の位置から 1 行下に移動します。ResultSet のカーソルは、初
期状態では最初の行の前に位置付けられています。メソッド next の最初の呼び
出しによって、最初の行が現在の行になります。2 番目の呼び出しによって 2 
行目が現在の行になり、以降同様に続きます。 

現在の行で入力ストリームがオープンしている場合、next メソッドへの呼び出
しは暗黙的にそのストリームをクローズさせます。新しい行が読み込まれるとき
に、ResultSet オブジェクトの警告チェーンはクリアされます。

戻り値:
  新しい現在の行が有効な場合は true、それ以上行がない場合は false 
例外: 
  SQLException - データベースアクセスエラーが発生した場合

カーソルは初期状態で最初の行の1つ前にあることに注意して、「ResultSet」オブジェクトに含まれる全ての行を処理するような場合には次のように記述します。

Connection conn = null;

try {
  conn = DriverManager.getConnection(url, user, password);

  Statement stmt = conn.createStatement();
  String sql = "SELECT * FROM kabukatable";
  ResultSet rs = stmt.executeQuery(sql);

  while(rs.next()){
    /* 行からデータを取得 */
  }
}catch (SQLException e){
  out.println("SQLException:" + e.getMessage());
}

次に現在の行に含まれるカラムの値を取得してみます。カラムは色々なデータ型がありますので、カラムの型に対応した多くのgetXXXXメソッドが用意されています。例えばString型の結果が含まれているカラムから値を取得するには「ResultSet」インターフェースで用意されている"getString"メソッドを使います。

この ResultSet オブジェクトの現在行にある指定された列の値を、Java プログ
ラミング言語の String として取得します。 

パラメータ:
  columnName - 列の SQL 名 
戻り値:
  列値。値が SQL NULL の場合、返される値は null 
例外: 
  SQLException - データベースアクセスエラーが発生した場合

引数にカラム名を指定してメソッドを実行すると、現在の行の中の指定のカラムの値を取得することが出来ます。

データ型毎にメソッドが用意されていますが、一部を紹介すると次のようなものがあります。

boolean getBoolean(String columnName)
byte getByte(String columnName)
Date getDate(String columnName)
double getDouble(String columnName)
int getInt(String columnName)
long getLong(String columnName)
Timestamp getTimestamp(String columnName)

実際の使い方は次のようになります。

Connection conn = null;

try {
  conn = DriverManager.getConnection(url, user, password);

  Statement stmt = conn.createStatement();
  String sql = "SELECT * FROM kabukatable";
  ResultSet rs = stmt.executeQuery(sql);

  while(rs.next()){
    int code = rs.getInt("code");
    String company = rs.getString("company");
  }
}catch (SQLException e){
  out.println("SQLException:" + e.getMessage());
}

リソースの開放

使わなくなった「ResultSet」オブジェクトは"close"メソッドを使ってリソースを開放しておきましょう。

自動的にクローズされるとき、これを待つのではなく、ただちに ResultSet オ
ブジェクトのデータベースと JDBC リソースを解放します。 

注: ResultSet オブジェクトは、このオブジェクトを生成した Statement オブ
ジェクトが閉じられるとき、再実行されるとき、または一連の複数の結果から次
の結果を取り出すのに使用されるときに、その Statement によって自動的にク
ローズされます。ResultSet オブジェクトがガベージコレクトされるときにも自
動的にクローズされます。

例外: 
  SQLException - データベースアクセスエラーが発生した場合

また「Statement」オブジェクトも同様に"close"メソッドを使ってリソースを開放します。

自動的にクローズされるときに Statement オブジェクトのデータベースと 
JDBC リソースが解放されるのを待つのではなく、ただちにそれらを解放します。
データベースのリソースを占有するのを避けるために、通常は、作業が終了し
たらすぐにリソースを解放するようにしてください。 

すでにクローズされた Statement オブジェクトで close メソッドを呼び出す
と、操作は行われません。 

注: Statement オブジェクトは、ガベージコレクトされるときは自動的にクロー
ズされます。Statement オブジェクトがクローズされるとき、その現在の 
ResultSet オブジェクトが存在すれば、それもクローズされます。 

例外: 
  SQLException - データベースアクセスエラーが発生した場合

実際の使い方は次のようになります。

Connection conn = null;

try {
  conn = DriverManager.getConnection(url, user, password);

  Statement stmt = conn.createStatement();
  String sql = "SELECT * FROM kabukatable";
  ResultSet rs = stmt.executeQuery(sql);

  while(rs.next()){
    int code = rs.getInt("code");
    String company = rs.getString("company");
  }

  rs.close();
  stmt.close();
}catch (SQLException e){
  out.println("SQLException:" + e.getMessage());
}

サンプルプログラム

では簡単なサンプルプログラムで試してみましょう。

web.xmlファイルは下記のようにしました。

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  version="2.4">

  <servlet>
    <servlet-name>databasetest</servlet-name>
    <servlet-class>DatabaseTest2</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>databasetest</servlet-name>
    <url-pattern>/databasetest</url-pattern>
  </servlet-mapping>
</web-app>

プログラムは下記の通りです。

DatabaseTest2.java

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;

public class DatabaseTest2 extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException{

    response.setContentType("text/html; charset=Shift_JIS");
    PrintWriter out = response.getWriter();

    out.println("<html>");
    out.println("<head>");
    out.println("<title>データベーステスト</title>");
    out.println("</head>");
    out.println("<body>");

    Connection conn = null;
    String url = "jdbc:mysql://localhost/jdbctestdb";
    String user = "testuser";
    String password = "testpass";

    try {
      Class.forName("com.mysql.jdbc.Driver").newInstance();
      conn = DriverManager.getConnection(url, user, password);

      Statement stmt = conn.createStatement();
      String sql = "SELECT * FROM kabukatable";
      ResultSet rs = stmt.executeQuery(sql);

      while(rs.next()){
        int code = rs.getInt("code");
        String company = rs.getString("company");
        out.println("<p>");
        out.println("コード:" + code + ", 会社名:" + company);
        out.println("</p>");
      }

      rs.close();
      stmt.close();
    }catch (ClassNotFoundException e){
      out.println("ClassNotFoundException:" + e.getMessage());
    }catch (SQLException e){
      out.println("SQLException:" + e.getMessage());
    }catch (Exception e){
      out.println("Exception:" + e.getMessage());
    }finally{
      try{
        if (conn != null){
          conn.close();
        }
      }catch (SQLException e){
        out.println("SQLException:" + e.getMessage());
      }
    }

    out.println("</body>");
    out.println("</html>");
  }
}

上記をコンパイル後に「d:¥servlet-sample¥database¥WEB-INF¥classes¥」ディレクトリにクラスファイルを移動した後で、ブラウザで「http://localhost:8080/database/databasetest」へアクセスしてみます。

データの取得

今回のサンプルでは「kabukatable」テーブルにある全データを取り出して表示してみました。

( Written by Tatsuo Ikura )

関連記事 (一部広告含む)