リソースの開放

2.6 リソースの開放

 本節では、JDBCを利用してJavaプログラムからMySQLデータベースへ接続した際の、リソースの開放について学習します。

2.6.1 確実なリソースの開放

 データベースと連携するシステムはSQLの実行を頻繁に行うようになります。その際に、操作するデータの量が多くなると、リソースがシステムのパフォーマンスに影響します。その為、リソースの開放は確実に行う必要があります。本テキストでこれまで作成してきたプログラムを見ると、SQL文の実行中に例外が発生した場合、データベースが接続された状態のままになってしまっています。例外が発生した場合でもリソースを開放する処理が行われるように、例外処理に注意してリソースを確実に開放する方法を学習しましょう。

 では、どのように記述すれば確実なリソースの開放が行えるのか実際にプログラムを作成してみましょう。

リソースの開放を行うプログラム

 このプログラムは、データベースへ接続し、テーブルに登録されたデータを全て表示するプログラムです。SQL文を実行中にエラーが発生した場合でも、リソースの開放が行われるように例外処理を記述しています。

① ソース・フォルダー      :myjdbc_kanda/src
② パッケージ          :jp.co.f1.jdbc.ch02
③ 名前             :SampleSelect2
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる

➢ SampleSelect2.java
package jp.co.f1.jdbc.ch02;

import java.sql.*;

public class SampleSelect2 {

	//接続用の情報をフィールドに定数として定義
	private static String RDB_DRIVE="com.mysql.jdbc.Driver";
	private static String URL="jdbc:mysql://localhost/mybookdb";
 	private static String USER="bms";
 	private static String PASSWD="bms123";
 
 	public static void main(String[] args) {
 
 		Connection con = null;
 		Statement smt = null;
 
 		try {
 			Class.forName(RDB_DRIVE);
 			con = DriverManager.getConnection(URL,USER,PASSWD);
 			smt = con.createStatement();
 			String sql = "SELECT * FROM bookinfo";
 			ResultSet rs = smt.executeQuery(sql);
 
 			while (rs.next()) {
 				System.out.println("isbn -> "   + rs.getString("isbn") +
 						" title -> " + rs.getString("title") +
 						" price-> "  + rs.getString("price"));
 			}
 
 		} catch (Exception e) {
 			System.out.println("JDBCデータベース接続エラー" + e);
 
 		} finally {
 			try {
 				if (smt != null) {
 					System.out.println("SQLステートメントをクローズしました。");
 					smt.close();
 				}
 				if (con != null) {
 					System.out.println("DB接続をクローズしました。");
 					con.close();
 				}
 
 			} catch (SQLException ignore) {
 				//例外処理の無視
 			}
 		}
 	}
 }

実行結果

解説

 このプログラムは2.1節で学習したSampleSelect.javaを改良したプログラムです。大きな違いは34行目から48行目で、finally処理を追加し、その中でリソース(smt、com)の開放を行なっている点です。

 try~catchにfinallyブロックを追加する事で、正常時でも例外が発生した場合でも必ず処理されるルートを作成します。finallyブロックにSQLステートメント(smt)とデータベース接続(con)の開放処理を行うことで確実にリソースの開放が行えるようになります。
 なお、例外が発生した場所によってはリソースを取得していない場合があるため、36行目と40行目で開放する前にnullチェックを行っています。
   34: } finally {
   35: try {
   36: if (smt != null) {
   37: System.out.println("SQLステートメントをクローズしました。");
   38: smt.close();
   39: }
   40: if (con != null) {
   41: System.out.println("DB接続をクローズしました。");
   42: con.close();
   43: }
   44:
   45: } catch (SQLException ignore) {
   46: //例外処理の無視
   47: }
   48: }

 このプログラムでは以下ようにfinallyブロックが実行されます。

 ① 正常処理の場合
 正常処理を行なってfinallyブロックが実行される場合、smtとconは両方とも取得されているので、finallyブロックでは両方のリソースの開放が行われる。

 ② conを取得するまでに例外が発生
 conを取得するまでに例外が発生した場合、smtとconは両方とも取得されてないので、finallyブロックでは両方ともリソースの開放は行われない。

 ③ smtを取得するまでに例外が発生
 smtを取得するまでに例外が発生した場合、conのみ取得されsmtは取得されていないので、finallyブロックではconのみのリソースの開放が行われる。

ポイント
  • リソースの開放は確実に行うためにfinallyブロックで行う。
  • close()メソッドを実行することで、ConnectionオブジェクトとStatementオブジェクトのリソースを解放する。
  • リソースを解放する場合、リソースがあるか判断してから解放処理を行う。

NEXT>> 2.7 本章のまとめ