ついでに例外が起こる可能性のある処理を try-catch文 で囲みます。例外処理を加えると難しく感じるため、前回まではあえて省いていました。そろそろ大きな流れはつかめたと思いますので、例外処理を加えて書いています。
実際のシステムでは、ユーザーはプログラマーの予想を超える操作をするものです。システムを停止させないためには例外処理は欠かせません。これを機会に例外処理に慣れてください。
また前回まではデータベースに接続する時、クラスをインスタンス化せずに static メソッドでコネクションを得ていましたが、今回は SampleDb030 クラスをインスタンス化して利用する方法に変更してみました。この方法もよく使われるので覚えておいてください。
Connection con = SampleDb030.getConnection();
↓
SampleDb030 db = new SampleDb030();
以下の操作を始める前に、データベース SampleDB030.mdb の テーブル T01Prefecture を開き、 47 沖縄県 の下にレコードがある場合は、あらかじめ削除しておいてください。

【1】sample215 フォルダをフォルダごとコピーして、sample216 フォルダを作ります。

【2】今回は以下のようなファイル構成になりますので、コピーした余計なものは削除してください。

*データベースに接続する部分を変更しますので、「SampleDb030.class」ではなく、「SampleDb030.java」を使います。SampleDb030.javaは以下に掲載します。
【3】SampleDb030.java と PrefTest.java を以下のように変更します。
*「\」はWindowsではエンマークのことです。
保存先 C:\java\sample216
ファイル名 SampleDb030.java
import java.sql.*;
class SampleDb030{
private Connection con = null;
private Statement stmt = null;
private ResultSet rs = null;
public void open() {
String url = "jdbc:odbc:SampleDB030";
String user = "";
String pass = "";
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
con = DriverManager.getConnection(url,user,pass);
stmt = con.createStatement();
} catch (Exception e) {
e.printStackTrace();
}
}
public void close() {
try {
if (rs != null){
rs.close();
}
if (stmt != null){
stmt.close();
}
if (con != null){
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public ResultSet executeQuery(String sql) {
if (stmt != null){
try {
rs = stmt.executeQuery(sql);
} catch (SQLException e) {
e.printStackTrace();
}
}
return rs;
}
public int executeUpdate(String sql) throws SQLException {
int num = 0;
if(stmt != null){
num = stmt.executeUpdate(sql);
}
return num;
}
}
保存先 C:\java\sample216
ファイル名 PrefTest.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.sql.*;
import java.util.*;
class PrefFrame extends JFrame implements ActionListener, ListSelectionListener {
Container cp;
JLabel lb1;
JList lt;
JButton btn1, btn2, btn3, btn4;
JMenuItem mi1, mi2, mi3, mi4, mi5, mi6;
String[] tkn;
public PrefFrame(String title) {
//フレームのタイトル
setTitle(title);
//コンテンツペイン取得
cp = getContentPane();
//ウィンドウを閉じる時
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
showExitDialog();
}
});
//Look&Feelの設定
/*
String type = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
try {
UIManager.setLookAndFeel(type);
} catch ( Exception e ) {
System.out.println("例外発生:" + e );
}
*/
//メニューバーの生成
JMenuBar mb = new JMenuBar();
//メニューの生成
JMenu mn1 = new JMenu("ファイル");
JMenu mn2 = new JMenu("編集");
JMenu mn3 = new JMenu("検索");
//メニュー項目の生成
mi1 = new JMenuItem("追加");
mi2 = new JMenuItem("更新");
mi3 = new JMenuItem("削除");
mi4 = new JMenuItem("終了");
mi5 = new JMenuItem("検索");
mi6 = new JMenuItem("全件表示");
//イベントリスナーの登録
mi1.addActionListener(this);
mi2.addActionListener(this);
mi3.addActionListener(this);
mi4.addActionListener(this);
mi5.addActionListener(this);
mi6.addActionListener(this);
//メニューへの追加
mn1.addSeparator(); //セパレーター
mn1.add(mi4);
mn2.add(mi1);
mn2.add(mi2);
mn2.add(mi3);
mn3.add(mi5);
mn3.add(mi6);
//メニューバーへの追加
mb.add(mn1);
mb.add(mn2);
mb.add(mn3);
//メニューバーをフレームへ追加
setJMenuBar(mb);
//ラベル
lb1 = new JLabel();
lb1.setHorizontalAlignment(SwingConstants.CENTER);
lb1.setOpaque(true);
lb1.setFont(new Font("Dialog", Font.PLAIN, 12));
lb1.setBackground(Color.WHITE);
cp.add(lb1, BorderLayout.NORTH);
//リスト
lt = new JList();
lt.setFont(new Font("Dialog", Font.PLAIN, 14));
lt.setForeground(new Color(64, 64, 64));
lt.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
lt.addListSelectionListener(this);
JScrollPane sp = new JScrollPane(lt);
cp.add(sp, BorderLayout.CENTER);
//パネル
JPanel pn1 = new JPanel();
pn1.setLayout(new GridLayout(1, 4));
//ボタンの設定
btn1 = new JButton("追加");
btn2 = new JButton("更新");
btn3 = new JButton("削除");
btn4 = new JButton("終了");
btn4.setForeground(new Color(255, 0, 0));
btn1.addActionListener(this);
btn2.addActionListener(this);
btn3.addActionListener(this);
btn4.addActionListener(this);
pn1.add(btn1);
pn1.add(btn2);
pn1.add(btn3);
pn1.add(btn4);
//パネルを追加
cp.add(pn1, BorderLayout.SOUTH);
//データ表示
prefAll();
}
public void actionPerformed (ActionEvent e) {
Object obj = e.getSource();
if (obj == btn1 || obj == mi1) {
prefInsert();
}else if (obj == btn2 || obj == mi2) {
prefUpdate();
}else if (obj == btn3 || obj == mi3) {
prefDelete();
}else if (obj == btn4 || obj == mi4) {
showExitDialog();
}else if (obj == mi5) {
prefSearch();
}else if (obj == mi6) {
prefAll();
}
}
public void valueChanged (ListSelectionEvent e) {
try {
String str = (String)lt.getSelectedValue();
if(str != null){
StringTokenizer st = new StringTokenizer(str, ",");
int arraySize = st.countTokens();
tkn = new String[arraySize];
int i = 0;
while(st.hasMoreTokens()) {
tkn[i] = st.nextToken();
i++;
}
lb1.setText("PREF_CD:" + tkn[0] + " PREF_NAME:" + tkn[1]);
lb1.setForeground(Color.BLUE);
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
private void prefDisplay (ResultSet rs) {
tkn = null;
ArrayList<String> listData = new ArrayList<String>();
try {
//結果セットからデータを取り出す next()で次の行に移動
int count = 0;
while(rs.next()) {
int prefCd = rs.getInt("PREF_CD");
String prefName = rs.getString("PREF_NAME");
listData.add(prefCd + "," + prefName);
count++;
}
lt.setListData(listData.toArray());
lb1.setForeground(Color.BLUE);
if(count == 0) {
lb1.setText("該当するレコードがありません。");
}else{
lb1.setText(count + "件表示しました。");
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void showExitDialog () {
//終了ダイアログボックスの表示
int ret = JOptionPane.showConfirmDialog (cp, "プログラムを終了しますか?", "確認", JOptionPane.YES_NO_OPTION);
if(ret == JOptionPane.YES_OPTION) {
System.exit(0);
}
}
private void prefInsert () {
//追加
String message = "PREF_CD を入力してください。";
String title = "追加";
try {
String prefCd = JOptionPane.showInputDialog (cp, message, title,JOptionPane.QUESTION_MESSAGE);
if(prefCd != null && !prefCd.equals("")) {
String message2 = "PREF_NAME を入力してください。";
String prefName = JOptionPane.showInputDialog (cp, message2, title,JOptionPane.QUESTION_MESSAGE);
if(prefName != null && !prefName.equals("")) {
String mySql = "insert into T01Prefecture values(" + prefCd + ", '" + prefName + "')";
System.out.println(mySql);
SampleDb030 db = new SampleDb030();
db.open();
int num = db.executeUpdate(mySql);
db.close();
prefAll();
lb1.setText("登録しました。");
}
}
} catch (SQLException e) {
e.printStackTrace();
lb1.setText("登録できませんでした。");
lb1.setForeground(Color.RED);
} catch (Exception e) {
e.printStackTrace();
}
}
private void prefUpdate () {
//更新
String prefCd = (tkn != null) ? tkn[0] : null;
String prefName = (tkn != null) ? tkn[1] : null;
Object nameObj = null;
try {
if(prefCd != null) {
String message = "「" + prefCd + " " + prefName + "」の\n新しい PREF_NAME を入力してください。";
String title = "更新";
nameObj = JOptionPane.showInputDialog (cp, message, title,JOptionPane.QUESTION_MESSAGE, null, null, prefName);
}else{
JOptionPane.showMessageDialog(cp, "先に都道府県を選択してください。");
}
if(nameObj != null) {
prefName = (String)nameObj;
String mySql = "update T01Prefecture set PREF_NAME = '" + prefName + "' where PREF_CD = " + prefCd;
System.out.println(mySql);
SampleDb030 db = new SampleDb030();
db.open();
int num = db.executeUpdate(mySql);
db.close();
prefAll();
lb1.setText(num + "件更新しました。");
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void prefDelete () {
//削除
String prefCd = (tkn != null) ? tkn[0] : null;
String prefName = (tkn != null) ? tkn[1] : null;
int ret = -9;
try {
if(prefCd != null) {
String message = "「" + prefCd + " " + prefName + "」を削除しますか?";
String title = "削除";
ret = JOptionPane.showConfirmDialog (cp, message, title, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
}else{
JOptionPane.showMessageDialog(cp, "先に都道府県を選択してください。");
}
if(ret == JOptionPane.OK_OPTION) {
String mySql = "delete from T01Prefecture where PREF_CD = " + prefCd;
System.out.println(mySql);
SampleDb030 db = new SampleDb030();
db.open();
int num = db.executeUpdate(mySql);
db.close();
prefAll();
lb1.setText(num + "件削除しました。");
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void prefSearch () {
//検索
String message = "PREF_NAME の一部を入力してください。";
String title = "検索";
try {
String prefName = JOptionPane.showInputDialog (cp, message, title, JOptionPane.QUESTION_MESSAGE);
if(prefName != null && !prefName.equals("")) {
String mySql = "select * from T01Prefecture where PREF_NAME like '%" + prefName + "%'";
System.out.println(mySql);
SampleDb030 db = new SampleDb030();
db.open();
ResultSet rs = db.executeQuery(mySql);
prefDisplay(rs);
db.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void prefAll () {
//全件表示
try {
String mySql = "select * from T01Prefecture order by PREF_CD";
System.out.println(mySql);
//SampleDb030をインスタンス化
SampleDb030 db = new SampleDb030();
//データベースに接続
db.open();
//検索するSQL実行
ResultSet rs = db.executeQuery(mySql);
//データ表示
prefDisplay(rs);
//オブジェクトを解放
db.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class PrefTest {
public static void main(String args[]) {
PrefFrame frm = new PrefFrame("都道府県マスター");
//フレームの設定
frm.setLocation(300, 200);
frm.setSize(250, 350);
frm.cp.setBackground(Color.LIGHT_GRAY);
frm.setVisible(true);
}
}
【4】コマンドプロンプトを起動して、カレントディレクトリを sample216 に切り替えます。

【5】javac PrefTest.java と入力し、コンパイルします。

【6】java PrefTest と入力し、プログラムを実行します。

【7】都道府県マスターが表示されました。新たに件数が表示されています。

【8】コマンドプロンプトには表示に使用したSQL文が出力されています。

*System.out.println(mySql); の文をコメントにすると出力されなくなります。
【9】「追加」ボタンをクリックします。

【10】99 と入力し、「了解」ボタンをクリックします。

【11】ハワイ と入力し、「了解」ボタンをクリックします。

【12】ダイアログボックスから入力したデータが登録され、メッセージが表示されます。

【13】ハワイ を選択してから、「更新」ボタンをクリックします。

【14】PREF_NAME を グアム に変更して、「了解」ボタンをクリックします。

【15】データが更新され、メッセージが表示されます。

【16】グアム を選択してから、「削除」ボタンをクリックします。

【17】削除するダイアログボックスが表示されたら、「了解」ボタンをクリックします。

【18】データが削除され、メッセージが表示されます。

【19】メニューから「検索」を選択します。

【20】長 と入力し、「了解」ボタンをクリックします。

【21】条件に合うデータが抽出され、メッセージが表示されます。

*あいまい検索ですので、文字列中に含まれていれば抽出されます。
【22】メニューから「全件表示」を選択します。

【23】データが全件表示されました。

【24】今度はわざと既に登録されている番号で追加してみます。1は北海道で登録済みです。

【25】PREF_CDが重複するので、「登録できませんでした。」というメッセージが表示されます。

【26】コマンドプロンプトにはエラー原因の詳細が出力されています。

*e.printStackTrace();で出力しています。
【27】あとは画面をいろいろ操作して、動作とSQL文を確認してください。。
「追加」、「更新」、「削除」、「検索」に使われたSQL文はコマンドプロンプトに出力されるので参考にしてください。データに何らかの変更があった場合は、リストも更新しなければならないため、select文が実行されています。

【解説】
■SampleDb030.java側
(1)SampleDb030クラスからデータベースを操作する方法を変更し、新しくいくつかのメソッドを用意しました。これらは static メソッドではないので、インスタンスを生成してから利用します。
open() データベースに接続
close() オブジェクトを解放
executeQuery() select文を実行
executeUpdate() insert、update、delete文を実行
(2)executeQuery()メソッドはSQL文を実行し、検索の結果セットを返します。
public ResultSet executeQuery(String sql) {
(3)executeUpdate()メソッドはSQL文を実行し、追加、更新、削除されたレコード数を返します。
public int executeUpdate(String sql) throws SQLException {
また SQLException という例外が発生したときに、このメソッド内で例外処理を行わず、 throws SQLException で呼び出し元に処理を委ねている点に注目してください。
(4)各メソッドではif文で、変数 rs、stmt、con が nullではない場合に処理を行うようにしています。
if (rs != null){
}
(5)例外が起こる可能性のある処理を try-catch文 で囲んでいます。
■PrefTest.java側
(1)ラベルにメッセージを表示するようにしたため、ラベルをインスタンス化する方法を変えました。ラベルのテキストは必要な場所で設定するようにしています。
lb1 = new JLabel("ボタンをクリックしてください。", SwingConstants.CENTER);
↓
lb1 = new JLabel();
lb1.setHorizontalAlignment(SwingConstants.CENTER);
lb1.setText("登録しました。");
(2)PrefFrameクラスのコンストラクタの最後で prefAll() メソッドを呼び出してレコードを表示するように変更しました。
prefDisplay();
↓
prefAll();
(3)各メソッドでは例外が起こる可能性のある処理を try-catch文 で囲んでいます。そのため少し複雑になっていますが、基本的な流れは変わりません。
(4)prefDisplay()メソッドには大きな変更があります。メソッドの引数で結果リストを受け取り、画面上のリストへの表示を専門に行うようにしました。
private void prefDisplay (ResultSet rs) {
(5)prefDisplay()メソッドでは、リストを選択した時に代入される変数 tkn を null で初期化しています。これはリストを再表示する場合は選択を解除したいためです。
tkn = null;
また while文で、レコード数をカウントしてメッセージに利用しています。
int count = 0;
while(rs.next()) {
省略
count++;
}
(6)データベースに接続して閉じるまでの基本的な流れ
・SampleDb030をインスタンス化
SampleDb030 db = new SampleDb030();
・データベースに接続
db.open();
・検索するSQL実行
ResultSet rs = db.executeQuery(mySql);
または更新するSQL実行
int num = db.executeUpdate(mySql);
・データ表示
prefDisplay(rs); または prefAll();
・オブジェクトを解放
db.close();
(7)prefAll()メソッドは、全件表示するSQL文の結果リストを引数に、prefDisplay()を呼び出しています。
prefDisplay(rs);
つまり、全件表示したいときはprefAll()メソッドを使い、条件に合うレコードを表示したいときは、抽出するSQL文の結果リストを引数に、prefDisplay()メソッドを呼び出します。どちらも最終的には必ずprefDisplay()メソッドが呼び出されます。
(8)SampleDb030クラスのexecuteUpdate()メソッドでスローされた例外は、prefInsert ()メソッドではキャッチして、ラベルにメッセージを表示しています。
catch (SQLException e) {
e.printStackTrace();
lb1.setText("登録できませんでした。");
lb1.setForeground(Color.RED);
}
*更新、削除は既存データへの処理で、しかもPREF_CDは変更できないような仕組みになっているため、追加に比べると例外が起こる可能性は低いです。そのため Exception で汎用の例外処理だけを行い、細かい例外処理はしていません。
(9)各catch文では、例外の内容を出力するメソッドを変えて、詳細な内容が表示されるようにしました。printStackTrace()は例外が発生した場所と行番号を、発生したところからたどって表示します。
System.out.println("例外発生:" + e );
↓
e.printStackTrace();
【ワンポイント】
追加、修正、削除などのSQL文を実行したときは、データベースを閉じるか、コミット(Commit)しないと反映されません。コミットするにはコネクションのメソッドを利用する必要があります。
con.commit();
そこで簡単に処理するため、リストを再表示する前にデータベースを閉じています。
db.close();
prefAll();