Revised: 9th/Sep./2002
GUIで入力したSQL文に応じてテーブルの内容が変わるように変更しましょう。前節のサンプルはアプレットでしたが、本節ではそれを変更してアプリケーションとして実装します。
SQL文でデータを取得するのはSELECTステートメントです。次のサンプルはテキスト・フィールドに入力したSQL文でJTableを変更できるように変更してみましょう。次の例は、JDBCSwingDemoクラスにJTextField, JButtonを追加し、JButtonオブジェクトには、イベント・リスナを登録しています。ボタンの押下を検知するリスナ・メソッドでは、テキスト・フィールドの文字列をSQL文として発行し、JTableオブジェクトのモデルを変更しています。
前節のPersistenceManagerクラスを使いますので、前節のコードをコンパイルしてから以下のコードのコンパイルを実行してください。
JDBCSwingQuery.java:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import java.sql.*;
import java.util.*;
class JDBCSwingQuery extends JFrame implements ActionListener {
PersistenceManager persistMgr;
TableModel model;
ResultSet rs;
JTable table;
JTextField queryField;
JButton queryButton;
public static void main(String[] args) {
JDBCSwingQuery obj = new JDBCSwingQuery();
}
JDBCSwingQuery() {
// DBMS への接続
persistMgr = new PersistenceManager();
// SQL 文の発行とモデルの取得
try {
rs = persistMgr.executeSQL("SELECT * FROM addr;");
model = new DataModel(rs);
} catch (SQLException e) {
e.printStackTrace();
return;
}
// JTable の作成
table = new JTable(model);
JScrollPane scrollpane = new JScrollPane(table);
// コンポーネントの作成
queryField = new JTextField("SELECT * FROM addr;");
queryButton = new JButton("Submit");
queryButton.addActionListener(this);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(2, 1));
panel.add(queryField);
panel.add(queryButton);
// コンテント・ペインの取得
Container cont = getContentPane();
// コンテント・ペインに追加
cont.add(panel, BorderLayout.NORTH);
cont.add(scrollpane, BorderLayout.CENTER);
// JFrame の作成
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
public void actionPerformed(ActionEvent ae) {
String str = queryField.getText();
try {
rs = persistMgr.executeSQL(str);
model = new DataModel(rs);
} catch (SQLException e) {
e.printStackTrace();
return;
}
table.setModel(model);
}
}
このサンプルをコンパイル/実行して、SELECT文を発行してみてください。尚、前節のPersistenceManagerクラス、DataModelクラスを使うので、前節のサンプルをコンパイルしてから実行してください。
C:\java>javac JDBCSwingQuery.java C:\java>java JDBCSwingQuery
![]() |
| 図:JDBCSwingQueryの実行結果 |
SQL文において、テーブルの定義や変更、削除を行うDDL (Data Definition Language)、アクセス権限、特権を管理するDCL (Data Control Language)はResultSetを返しません。また、データを操作するDML (Data Manipulate Language)でも、DELETE文やINSERT文もResultSetを返しません。前節のサンプルを、これらのSQL文も発行できるように変更しましょう。
前節のサンプルに、挿入/削除用のテキスト・フィールドを追加し、PersistenceManagerクラスに挿入/削除用のメソッドを追加します。挿入/削除などのSQL文の発行では、StatementのexecuteUpdate(String sql)メソッドを使います。このメソッドの戻り値型はintであり、INSERT文、UPDATE文、DELETE文の場合は行数、SQL DDLのような何も返さないSQL文の場合は0を返します。
JDBCSwingUpdate.java:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import java.sql.*;
import java.util.*;
class JDBCSwingUpdate extends JFrame implements ActionListener {
PersistenceManager persistMgr;
TableModel model;
ResultSet rs;
JTable table;
JTextField queryField;
JButton queryButton;
JTextField updateField;
JButton updateButton;
public static void main(String[] args) {
JDBCSwingUpdate obj = new JDBCSwingUpdate();
}
JDBCSwingUpdate() {
// DBMS への接続
persistMgr = new PersistenceManager();
// SQL 文の発行とモデルの取得
try {
rs = persistMgr.executeSQL("SELECT * FROM addr;");
model = new DataModel(rs);
} catch (SQLException e) {
e.printStackTrace();
return;
}
// JTable の作成
table = new JTable(model);
JScrollPane scrollpane = new JScrollPane(table);
// コンポーネントの作成
queryField = new JTextField("SELECT * FROM addr;");
queryButton = new JButton("Submit");
queryButton.addActionListener(this);
JPanel queryPanel = new JPanel();
queryPanel.setLayout(new GridLayout(2, 1));
queryPanel.add(queryField);
queryPanel.add(queryButton);
// executeUpdate()用のテキスト・フィールドの作成
updateField = new JTextField(
"INSERT INTO addr VALUES ('Google', 'http://www.google.co.jp/');");
updateButton = new JButton("DELETE/INSERT");
updateButton.addActionListener(this);
JPanel updatePanel = new JPanel();
updatePanel.setLayout(new GridLayout(2, 1));
updatePanel.add(updateField);
updatePanel.add(updateButton);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(2, 1));
panel.add(queryPanel);
panel.add(updatePanel);
// コンテント・ペインの取得
Container cont = getContentPane();
// コンテント・ペインに追加
cont.add(panel, BorderLayout.NORTH);
cont.add(scrollpane, BorderLayout.CENTER);
// JFrame の作成
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == queryButton) {
String str = queryField.getText();
try {
rs = persistMgr.executeSQL(str);
model = new DataModel(rs);
} catch (SQLException e) {
e.printStackTrace();
return;
}
table.setModel(model);
} else if (ae.getSource() == updateButton) {
String str = updateField.getText();
try {
persistMgr.executeUpdate(str);
} catch (SQLException e) {
e.printStackTrace();
return;
}
table.setModel(model);
}
}
}
class PersistenceManager {
Statement stmt;
// DBMS への接続
PersistenceManager() {
try {
// JDBC Driver の登録
Class.forName("com.mysql.jdbc.Driver").newInstance();
// データベースへの接続
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost/test", "root", "passwd");
// SQL ステートメント・オブジェクトの作成
stmt = con.createStatement();
} catch (Exception e) {
e.printStackTrace();
}
}
// SQL 文の発行
ResultSet executeSQL(String str) throws SQLException {
return stmt.executeQuery(str);
}
// 挿入/削除用のメソッド
int executeUpdate(String str) throws SQLException {
return stmt.executeUpdate(str);
}
}
本節ではソースコードをすっきりさせるために前節のソースコードを書き換えてしまいましたが、前節のソースコードのクラスを継承して新規のサブクラスを作成する事もできます。本番稼動のシステムに対しては、サブクラス化による機能追加の方が望ましいことが殆どです。前節のPersistenceManagerクラスを継承してサブクラスを作り、executeUpdateメソッドをオーバーライドしてください。このとき、PersistenceManagerクラスのインスタンス化は、新しく作ったサブクラスをインスタンス化するにように変更する必要があります。
C:\java>javac JDBCSwingUpdate.java C:\java>java JDBCSwingUpdate
![]() |
| 図:JDBCSwingUpdateの実行結果 |
前節までで、ResultSetを返すexecuteQuery()、返さないexecuteUpdate()を利用しました。JDBCではもう一つSQL文発行用のメソッドexecute()が用意されています。これは、複数のResultSetを返す可能性のあるSQL文発行用のメソッドであり、ResultSetを一つでも返す場合はtrue、さもなくばfalseを返します。本節では、このメソッドを使って、一つのテキスト・フィールドに任意SQL DML, SQL DDL, SQL DCLを入力してRDBMSに問い合わせるようにします。また、Update系のSQLに対しては、最後に発行したResultSetが返るSQLを再発行して、即時的にJTableが変更されるように工夫します。本ページ最初のサンプルから呼び出すPersistenceManagerクラスのSQL発行用のメソッドexecuteSQL()だけ変更します。
PersistenceManager.java:
import java.sql.*;
class PersistenceManager {
Statement stmt;
String SQL = "";
// DBMS への接続
PersistenceManager() {
try {
// JDBC Driver の登録
Class.forName("com.mysql.jdbc.Driver").newInstance();
// データベースへの接続
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost/test", "root", "passwd");
// SQL ステートメント・オブジェクトの作成
stmt = con.createStatement();
} catch (Exception e) {
e.printStackTrace();
}
}
// SQL 文の発行
ResultSet executeSQL(String str) throws SQLException {
try {
if (stmt.execute(str)) {
// SQL ステートメントの発行
SQL = str;
return stmt.getResultSet();
} else {
return stmt.executeQuery(SQL);
}
} catch (Exception e) {
e.printStackTrace();
return stmt.executeQuery(SQL);
}
}
}
一般に、DMLのResultSetを返すSQL文の発行メソッドはexecuteQuery()であり、ResultSetを返さないSQL文はexecuteUpdate()メソッドを使います。そして、複数のResultSetを返すかもしれないSQL文に対してはexecute()メソッドを用います。このメソッドは指定されたSQL文を発行後、ResultSetが一つでも返る場合にはtrueを返し、それ以外にはfalseを返します。このサンプルは、execute()メソッドを使って、ResultSetが返るかどうかで場合分けしています。返る場合はそのままスルーしてString SQLにそのSQL文を保存し、ResultSetを返します。返らない場合は、String SQLに保持されているResultSetを返すSQL文を再発行して、そのResultSetを返します。
このサンプルをコンパイル/実行して、ResultSetを返さないINSERTステートメント、DELETEステートメントなどを発行してみてください。
PersistenceManagerクラスのコンパイル
>javac PersistenceManager.java
これで"PersistenceManager.class"が更新されました。main()メソッドが含まれる"JDBCSwingQuery.java"を実行してください。
JDBCSwingQueryの実行
>java JDBCSwingQuery
![]() |
| 図:修正したJDBCSwingQueryの実行結果 |