jiichan.com

PROGRAMMING

JDBCによるデータベース操作

アプリケーション、特に業務用のシステム構築には、データベース接続は 必須となるのでJDBCを使ってデータベースを操作してみる。データベースはMySQLを使用。

JDBCドライバの準備とインストール

JDBCドライバは各データベースごとに準備されている。
今回はMySQLを使用するのでMySQL用のJDBCドライバ(MySQL Connector/J)を準備する。
1. MySQLのサイトから mysql-connector-java-gpl-x.x.x.msiをダウンロードする。 サイトのDownloadをクリックすると画面が変わり、Login SignUpのボタンが現れるが、無視して下部の 「No thanks, just start my download.」をクリックするとダウンロードが始まる。
ダウンロードの場所は適当に。x.x.xはバージョン番号。
2. ダウンロードしたmsiファイルをダブルクリックしてインストール。 Cドライブにフォルダ「mysql-connector-java-x.x.x」が作られる。 3. フォルダの中にmysql-connector-java-x.x.x-bin.jar(JDBCドライバ)が配置されている。 4. クラスパスは環境変数CLASSPATHにセットするか、各IDEでのセット方法に従う。 私の場合はNetBeansを使用しているので「プロジェクト」ウィンドウで「ライブラリ」ノードを右クリック、 「JAR/フォルダの追加」でセットしている。

データベース接続

データベースに接続するときには、JDBCドライバを最初に読み込む必要がある。


// JDBCドライバの読み込み
try {
	Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
	System.out.println("error:" + e.getMessage());
}

3行目:Class.forName("com.mysql.jdbc.Driver");がJDBCドライバを読み込んでいる部分。
ClassクラスのforNameメソッドでJDBCドライバのクラス名を指定する。

読み込んだ後にDriverManagerクラスのgetConnectionメソッドでデータベースに接続する。


// getConnectionのJDBCドライバURL
String url="jdbc:mysql://localhost/db?useUnicode=true&characterEncoding=utf8";
// データベースに接続
Connection con = DriverManager.getConnection(url, "user", "password");

urlに?以下を追加し、データベースの文字コードを明示的に指定しないとデータアップ時に文字化けする(シフトJISの場合ははSJIS)。
getConnectionメソッドで接続するとConnectionオブジェクトが得られる。
そのConnectionオブジェクトに対してデータベースを操作を行う。

データの取得

JDBCでのデータ取得の手順は概ね次のとおり。
1. SQL文を発行するためにStatementオブジェクトを取得。(下のコード6行目) ※ ConnectionオブジェクトのcreateStatementメソッドで得られる。 2. SQL文を発行し、問い合わせ結果であるResultSetオブジェクトを取得。(下のコード9行目) ※ Statementオブジェクトに対しexecuteQueryメソッドで得られる。 3. ResultSetオブジェクトの保持データをループ内で取り出し。(下のコード11~15行目) ※ ResultSetオブジェクトのnextメソッドの呼び出しを条件に各データにあった型で取り出す。 ※ データをStringとして取得する場合はgetString、intはgetInt、DateはgetDate。 4. 各オブジェクトを順に閉じメモリを開放。(下のコード17~19行目)


try {
	String name, address;
	// データベースへの接続
	Connection con = DriverManager.getConnection(url, "user", "password");
	// SQLを実行するためのステートメントの作成
	Statement stmt = con.createStatement();
	String sql = "SELECT * FROM tbl1";
	// SQLの実行 SELECT文にはexecuteQuery(sql)
	ResultSet rs = stmt.executeQuery(sql);
	// 結果の表示
	while (rs.next()) {
		name = rs.getString("name");
		address = rs.getString("address");
		System.out.println("お名前: " + name + ",ご住所: " + address);
	}
	// 後片付け
	rs.close();
	stmt.close();
	con.close();
} catch (SQLException e) {
	System.out.println("SQLException: " + e.getMessage());
}

データの変更・挿入・削除

「データの変更・挿入・削除」は、「データの取得」と違い、問い合わせ結果が無いのでResultSetオブジェクトは必要ない。 また、StatementオブジェクトのメソッドはexecuteUpdateを使用する。


try {
    // データベースへの接続
    Connection con = DriverManager.getConnection(url, "user", "password");
    // SQLを実行するためのステートメントの作成
    Statement stmt = con.createStatement();
    String sql = "UPDATE tbl1 SET name = '太郎' WHERE id = 1";
    // SQLの実行 UPDATE.INSERT.DELETE文にはexecuteUpdate(sql)
    int num = stmt.executeUpdate(sql);
    // 更新結果の表示
    System.out.println("更新件数は" + num + "です");
    // 後片付け
    stmt.close();
    con.close();
} catch (SQLException e) {
    System.out.println("SQLException: " + e.getMessage());
}

PreparedStatementの利用

ユーザーからの入力を含んだSQL文を発行する場合、文字列結合によるSQL文発行など、SQLインジェクションの危険がある。 固定のSQL文の場合はStatementオブジェクトの使用で問題は無いが、ユーザーからの入力を含んだSQL文を発行する場合は必ずプリペアドステートメントを使用する。
また、SQL文のコンパイルが、StatementではcreateStatement()メソッドで行われず、executeQuery(sql)メソッドで行われる。 PreparedStatementを用いた場合、prepareStatement(sql)メソッドで事前にコンパイルが行われており、 executeQuery()メソッドでは単に実行のみのため、繰り返しSQL文を発行する場合はパフォーマンスも良いらしい。
SQL文中の文字列のエスケープ処理も必要無い。


try {
    // データベースへの接続
    Connection con = DriverManager.getConnection(url, "user", "password");
    // SQLを実行するためのステートメントの作成
    String sql = "SELECT * FROM tbl1 WHERE (age = ?) AND (name = ?)";
	PreparedStatement pstmt = con.prepareStatement(sql);
	int age = txtAge.getText();
	String name = txtName.getText();
	pstmt.setInt(1, age);
	pstmt.setString(2, name);
    // SQLの実行 SELECT文にはexecuteQuery(sql)、更新系SQL文にはexecuteUpdate(sql)
    ResultSet rs = pstmt.executeQuery();
    // 結果の表示
    while (rs.next()) {
        address = rs.getString("address");
        System.out.println(name + "さんのご住所は: " + address);
    }
    // 後片付け
    rs.close();
    stmt.close();
    con.close();
} catch (SQLException e) {
    System.out.println("SQLException: " + e.getMessage());
}

5行目:SQL文の中でパラメータのプレース・ホルダ(?)が使われている。
6行目:prepareStatement(sql)でSQL文が解析されているので12行目のexecuteQuery()では実行のみ。
9行目:executeQuery()で実行前にsetXXX()でパラメータに値をセットする。最初の引数は?の順番で次は埋め込む値。