データベースアクセスBeanの作成
では、作成したmydatabaseデータベースのuserdataテーブルを利用するプログラムを作成してみましょう。ここでは、次のような形でWebアプリケーションを構成していくことにします。
- データベースアクセスBeanクラス
- 表示用JSP
- データベース操作用サーブレット
表示関係は、「index.jsp」からBeanクラスを利用して表示をさせることにします。レコードの新規登録や削除といった操作は、サーブレットに送信をし、そこからBeanを利用してデータベースの操作を行った後、「index.jsp」にリダイレクトする、といった形で動くようにしましょう。
Beanクラスの定義
では、データベース利用のためのプログラムを作成していきましょう。データベースへのアクセスを行うのは、DBAccessというクラスです。ここにデータベースを利用するために必要な機能をすべて用意しておくことにします。
package jp.codezine; import java.sql.*; import java.util.Properties; public class DBAccess { public Connection createConnection() throws ClassNotFoundException, SQLException { Connection conn = null; Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); Properties prop = new Properties(); prop.put("user", "user"); prop.put("password", "test"); conn = DriverManager.getConnection( "jdbc:derby:C:\\DerbyDatabases\\mydatabase", prop); conn.setAutoCommit(true); return conn; } public void addRecord(int n, String nm) { Connection conn = null; Statement state = null; try { conn = createConnection(); state = conn.createStatement(); String query = "insert into userdata values(" + n + ",'" + getSanitizedString(nm) + "')"; state.execute(query); } catch (Exception ex) { ex.printStackTrace(); } finally { try { state.close(); conn.close(); } catch (Exception ex) { } } } public void removeRecord(int n) { Connection conn = null; Statement state = null; try { conn = createConnection(); state = conn.createStatement(); String query = "delete from userdata where number=" + n; state.execute(query); } catch (Exception ex) { ex.printStackTrace(); } finally { try { state.close(); conn.close(); } catch (Exception ex) { } } } public String getAllRecord() { return getRecord("select * from userdata"); } public String getFindRecord(String s) { int n = 0; try { n = Integer.parseInt(s); } catch (NumberFormatException e) { e.printStackTrace(); } String q = "select * from userdata where number=" + n; System.out.println(q); return getRecord(q); } public String getRecord(String query){ String result = "<table border=\"1\">\n"; Connection conn = null; Statement state = null; ResultSet rs = null; try { conn = createConnection(); state = conn.createStatement(); rs = state.executeQuery(query); while (rs.next()) { int number = rs.getInt("number"); String name = rs.getString("name"); result += "<tr>"; result += "<td>" + number + "</td>"; result += "<td>" + name + "</td>"; result += "</tr>\n"; } result += "</table>\n"; } catch (Exception ex) { ex.printStackTrace(); } finally { try { rs.close(); state.close(); conn.close(); } catch (Exception ex) { } } return result; } // 無効化処理 public String getSanitizedString(String s) { return s.replaceAll("'", ""); } }
ここでは、データベースへの接続開始のための処理をcreateConnectionというメソッドにまとめ、それを呼び出して利用する形で各種のメソッドを用意してあります。用意してあるのは次のようなものです。
| メソッド名 | 機能 |
| addRecord | 引数の値をレコードとして登録する。 |
| removeRecord | 引数のnumberのレコードを削除する。 |
| getAllRecord | 全レコードを表示するHTMLソースを返す。 |
| getFindRecord | 引数のnumberのレコードを検索し表示するHTMLソースを返す。 |
これらのメソッドをJSP/サーブレットから呼び出すことでデータベースを利用できるようにするわけです。
データアクセスの流れ
データベースアクセスの基本的な手順は、どのような操作でも大体同じです。まず「ava.sql.Connection」クラスのインスタンスを作成し、これを利用して各種の操作を行うことになります。Connectionを取得し必要な処理を行うまでの部分が、データベースアクセスで最も面倒くさい部分といってよいでしょう。
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
まず最初に行うべきは、データベースにアクセスするためのドライバークラスのロードです。これは、Class.forNameを利用します。これで引数に指定したドライバークラスをロードすると、以後のデータベースへの接続にこのクラスを利用するようになります。
Java DBの場合、アクセスには2種類の方法があります。直接データベースにアクセスする方法と、Java DBをサーバとして起動し、クライアントからアクセスする方法です。ここでは直接アクセスをしていますので、そのためのドライバーとしてorg.apache.derby.jdbc.EmbeddedDriverクラスをロードします(サーバにクライアントとしてアクセスする場合には、org.apache.derby.jdbc.ClientDriverクラスを使います)。
Properties prop = new Properties(); prop.put("user", "user"); prop.put("password", "test");
続いて、データベースアクセスを行うのに必要なプロパティをPropertiesインスタンスとして用意しておきます。ここでは、アクセスに使うユーザ名とパスワードを、それぞれ"user"、"password"という名前のプロパティとしてPropertiesに追加しておきます。
conn = DriverManager.getConnection(
"jdbc:derby:C:\\DerbyDatabases\\mydatabase", prop);
必要なものが揃ったら、DriverManager.getConnectionを呼び出してConnectionインスタンスを作成します。このgetConnectionでは、引数にアクセスするデータベースと、その他必要な情報をまとめたPropertiesを渡しています。Java DBの場合、データベースは、「jdbc:derby:データベースの指定」という形になります(クライアントからサーバにアクセスをする場合には、「jdbc:derby://ホスト名:ポート番号/データベース指定」となります)。
conn.setAutoCommit(true);
Connection取得後、ここではオートコミット機能をONにしています。これはクエリー(SQLのコマンド文)を送信し実行するごとにトランザクションの開始と終了を自動的に行うものです。トランザクションは、関連する処理をまとめて実行するためのもので、データベースアクセスでは一定の処理をまとめて行うようにします。このsetAutoComitは、実行すると自動的にトランザクション処理を開始・終了してくれます。
ここまでで、Connection作成のための基本的な手続きは終わりました。続いて、実際にSQLのコマンドを送信して処理を行うことになります。このコマンドには、大きく分けて2つのものがあります。単にコマンドを実行するだけのものと、実行して結果を取得し、それを利用するものです。
まず「コマンドを実行して終わり」というタイプのものからです。レコードを追加したり削除したりといった操作は、ただ実行するだけで、その後に何らかの結果を受け取って処理するわけではありません。こうしたタイプのものは、実行は比較的簡単です。
state = conn.createStatement();
Connectionから「Statement」というインスタンスを作成します。このStatementを使ってSQLのコマンドを実行します。
String query = "insert into userdata values(" + n + ",'" + getSanitizedString(nm) + "')"; state.execute(query);
実行するSQLのコマンドをテキストとして用意し、これを引数にしてStatementのexecuteを呼び出します。これでコマンドが実行されます。単純にコマンドを実行するタイプのものは、これで終わりです。
一方、レコードを表示したり、検索結果を表示するようなコマンドは、もう少し複雑です。まずStatementを用意し、コマンドを実行するという手順は同じですが、扱いが多少異なります。
state = conn.createStatement(); rs = state.executeQuery(query);
こちらは、executeではなく、executeQueryというメソッドを利用しています。こちらは、SQLコマンドを送信し、結果を「ResultSet」というクラスのインスタンスとして受け取ります。このResultSetはデータベースからレコード情報を受け取るのに用いられるもので、この中から順にレコードの情報を取り出していくことができます。
while (rs.next()) { int number = rs.getInt("number"); String name = rs.getString("name"); result += "<tr>"; result += "<td>" + number + "</td>"; result += "<td>" + name + "</td>"; result += "</tr>\n"; } result += "</table>\n";
返されたResultSetから全レコードの情報を取り出しています。ResultSetは、カレントレコード(現在選択されているレコード)の概念を持っており、「getInt」「getString」といったメソッドを呼び出すことで、現在のカレントレコードの値を取り出すことができます。カレントレコードは、nextメソッドを呼び出すごとに移動していきます。一番最後のレコードまで移動し、更にnextを呼び出すとfalseが返され、whileから抜け出すことができます。
