DAOパターン

4.1 DAOパターン

 JDBCを利用したアプリケーションを作成する場合、DAOパターン・DTOパターンと呼ばれる2つのプログラムの設計パターンがよく利用されます。2つのデザインパターンは本来はセットで利用されるものですが、各々がどのような役割を果たすのか学習するため、本節ではDAOパターンに焦点をあてて解説します。

4.1.1 DAOパターンとは

 DAO(Data Access Object)パターンとはデータベースへのアクセスを行うクラスを作り、そのクラスを通してデータベースへアクセスするデザインパターンです。メインロジックのなかに記述されていたアクセス部分の処理を1つのクラスに集約し、データベースアクセスの窓口の役割を持たせます。

図 4.1.1 DAOパターンとデータベース接続

4.1.2 DAOパターンの基本的な構成とメリット

 DAOパターンを利用したプログラムでは、メインロジックとデータアクセスの処理を明確に分けてデザインされます。そのため、以下のようなメリットがあります。

  • アプリケーション内でメインロジックとデータベースアクセスの処理を明確に分けることで、独立性や拡張性を高め、修正や変更があった場合に、互いのクラスに影響を与えないようにする。
  • データベースアクセスの機能を1つのクラスに集約するため、アクセス箇所を特定しやすい。
  • データベースアクセス処理の重複した記述を防ぎ、ソースコードをシンプルにする。

図 4.1.2: DAOを利用したアプリケーション

DAOパターンを利用したプログラム

 このプログラムは、データベースへアクセスを行う処理をメソッド化し、1つのクラスとしてまとめたDAOパターンを利用したプログラムです。DAOパターンを使用したプログラムの動きを確認しましょう。
 なお、このプログラムではデータベースアクセスを行う「SampleDAO1.java」とプログラムのメイン処理を記述する「InsertProgram1.java」を作成します。

ソースコード

① ソース・フォルダー      :myjdbc_kanda/src
② パッケージ          :jp.co.f1.jdbc.ch04
③ 名前             :SampleDAO1

➢ SampleDAO1.java
package jp.co.f1.jdbc.ch04;

import java.sql.*;
import java.util.ArrayList;

public class SampleDAO1 {

	//接続用の情報をフィールドに定数として定義
	private static final String RDB_DRIVE="org.mariadb.jdbc.Driver";
 	private static final String URL="jdbc:mariadb://localhost/mybookdb";
 	private static final String USER="bms";
 	private static final String PASSWD="bms123";
 
 	// データベース接続を行うメソッド
 	// データベース接続用定義を基にデータベースへ接続し、戻り値としてコネクション情報を返す
 	private static Connection getConnection(){
 		try{
 			Class.forName(RDB_DRIVE);
 			Connection con = DriverManager.getConnection(URL, USER, PASSWD);
 			return con;
 		}catch(Exception e){
 			throw new IllegalStateException(e);
 		}
 	}
 
 	// データベースからisbnデータの検索を行うメソッド
 	// テーブルに登録された全てのisbnデータをArrayListへ格納し、戻り値として返す
 	public ArrayList<String> selectIsbnAll(){
 
 		// 変数宣言
 		Connection con = null;	// DBコネクション
 		Statement smt = null;	// SQLステートメント
 
 		// 配列宣言
 		ArrayList<String> list = new ArrayList<String>();
 
 		// SQL文作成
 		String sql = "SELECT isbn FROM bookinfo ORDER BY isbn";
 
 		try{
 			// DBに接続
 			con = SampleDAO1.getConnection();
 			smt = con.createStatement();
 
 			// SQL文発行
 			ResultSet rs = smt.executeQuery(sql);
 
 			// 検索結果をArrayListに格納
 			while(rs.next()){
 				list.add(rs.getString("isbn"));
 			}
 
 		}catch(SQLException e){
 			System.out.println("Errorが発生しました!\n"+e);
 		}finally{
 			// リソースの開放
 			if(smt != null){
 				try{smt.close();}catch(SQLException ignore){}
 			}
 			if(con != null){
 				try{con.close();}catch(SQLException ignore){}
 			}
 		}
 		return list;
 	}
 
 	// データベースからtitleデータの検索を行うメソッド
 	// テーブルに登録された全てのtitleデータをArrayListへ格納し、戻り値として返す
 	public ArrayList<String> selectTitleAll(){
 		// 変数宣言
 		Connection con = null;	// DBコネクション
 		Statement smt = null;	// SQLステートメント
 
 		// 配列宣言
 		ArrayList<String> list = new ArrayList<String>();
 
 		// SQL文
  		String sql = "SELECT title FROM bookinfo ORDER BY isbn";
 
 		try{
 			// DBに接続
 			con = SampleDAO1.getConnection();
 			smt = con.createStatement();
 
 			// SQL文発行
 			ResultSet rs = smt.executeQuery(sql);
 
 			// 検索結果をArrayListに格納
 			while(rs.next()){
 				list.add(rs.getString("title"));
 			}
 
 		}catch(SQLException e){
 			System.out.println("Errorが発生しました!\n"+e);
 		}finally{
 			// リソースの開放
 			if(smt != null){
 				try{smt.close();}catch(SQLException ignore){}
 			}
  			if(con != null){
  				try{con.close();}catch(SQLException ignore){}
  			}
  		}
  		return list;
  	}
  
  	// データベースからpriceデータの検索を行うメソッド
  	// テーブルに登録された全てのpriceデータをArrayListへ格納し、戻り値として返す
  	public ArrayList<Integer> selectPriceAll(){
  		// 変数宣言
  		Connection con = null;	// DBコネクション
  		Statement smt = null;	// SQLステートメント
  
  		// 配列宣言
  		ArrayList<Integer> list = new ArrayList<Integer>();
  
  		// SQL文
   		String sql = "SELECT price FROM bookinfo ORDER BY isbn";
  
  		try{
  			// DBに接続
  			con = SampleDAO1.getConnection();
  			smt = con.createStatement();
  
  			// SQL文発行
  			ResultSet rs = smt.executeQuery(sql);
  
  			// 検索結果をArrayListに格納
  			while(rs.next()){
  				list.add(rs.getInt("price"));
  			}
  
  		}catch(SQLException e){
  			System.out.println("Errorが発生しました!\n"+e);
  		}finally{
  			// リソースの開放
  			if(smt != null){
  				try{smt.close();}catch(SQLException ignore){}
  			}
  			if(con != null){
  				try{con.close();}catch(SQLException ignore){}
  			}
  		}
  		return list;
  	}
  
  	// 書籍情報を登録するメソッド
  	// 引数に渡された書籍情報をデータベースへ登録し、戻り値として登録件数を返す
  	public int insertBook(String isbn, String title, int price){
  		// 変数宣言
  		Connection con = null;	// DBコネクション
  		Statement smt = null;	// SQLステートメント
  
  		int rowsCount = 0;
  
  		// SQL文
  		String sql = "INSERT INTO bookinfo(isbn,title,price) " +
  				"VALUES('" + isbn + "','" + title + "'," + price + ")";
  
  		try{
  			// DBに接続
  			con = SampleDAO1.getConnection();
  			smt = con.createStatement();
  
  			// SQL文発行
  			rowsCount = smt.executeUpdate(sql);
  
  		}catch(SQLException e){
  			System.out.println("Errorが発生しました!\n"+ e +"\n");
  		}finally{
  			// リソースの開放
  			if(smt != null){
  				try{smt.close();}catch(SQLException ignore){}
  			}
  			if(con != null){
  				try{con.close();}catch(SQLException ignore){}
  			}
  		}
  		return rowsCount;
  	}
  
  }

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

➢ InsertProgram1.java
package jp.co.f1.jdbc.ch04;

import java.util.ArrayList;

public class InsertProgram1 {

	// 配列宣言
	private static ArrayList<String> isbnList = null;	// isbn情報格納用のリスト
	private static ArrayList<String> titleList = null;	// title情報格納用のリスト
 	private static ArrayList<Integer> priceList = null;	// price情報格納用のリスト
 
 	public static void main(String[] args) {
 		try{
 			// DAOオブジェクト化
 			SampleDAO1 objDao = new SampleDAO1();
 
 			// 書籍情報を取得するメソッドをDAOから呼び出す
 			isbnList = objDao.selectIsbnAll();	// isbn情報全て取得メソッド呼び出し
 			titleList = objDao.selectTitleAll();	// title情報全て取得メソッド呼び出し
 			priceList = objDao.selectPriceAll();	// price情報全て取得メソッド呼び出し
 
 			// 取得した書籍情報を表示
 			System.out.println("■登録SQL発行前の書籍一覧表示■");
 			display();
 
 			// 書籍情報を登録するメソッドをDAOから呼び出す
 			int rowsCount = objDao.insertBook("00008", "Strutsテキスト", 2000);
 			if(rowsCount > 0){
 				System.out.println(rowsCount + "件のレコードを登録しました。\n");
 			}
 
 			// 書籍情報を取得するメソッドをDAOから呼び出す
 			isbnList = objDao.selectIsbnAll();	// ISBN情報全て取得メソッド呼び出し
 			titleList = objDao.selectTitleAll();	// Title情報全て取得メソッド呼び出し
 			priceList = objDao.selectPriceAll();	// Price情報全て取得メソッド呼び出し
 
 			// 取得した書籍情報を表示
 			System.out.println("■登録SQL発行後の書籍一覧表示■");
 			display();
 
 		}catch(Exception e){
 			System.out.println("エラーが発生しました。" + e);
 		}
 	}
 
 	public static void display() {
 		for(int i=0;i<isbnList.size();i++){
 			System.out.print("ISBN→"  + isbnList.get(i)  + "\t");
 			System.out.print("Title→" + titleList.get(i) + "\t");
 			System.out.print("Price→" + priceList.get(i) + "\n");
 		}
 		System.out.println();
 	}
 
 }

実行結果

解説

 このプログラムは、DAOクラスを用いたデータベースアクセスを行い、書籍情報の表示と登録を行なっています。
 InsertProgram1の15行目ではDAOクラスであるSampleDAO1をオブジェクト化しています。DAOクラス内のメソッドは、インスタンスメソッドとして定義されているためオブジェクト化が必要です。
   15: SampleDAO1 objDao = new SampleDAO1();

 18行目ではSampleDAO1クラスのselectIsbnAll()メソッドを呼び出し、isbn情報を検索しています。その戻り値としてisbn情報が格納されたArrayListオブジェクトを受け取っています。
   18: isbnList = objDao.selectIsbnAll();

図 4.1.3: selectIsbnAll ()メソッドの流れ

 19行目と20行目も同様にSampleDAO1クラスから各々のメソッドを呼び出し、titleとpriceの格納されたArrayListオブジェクトを受け取ります。
   19: titleList = objDao.selectTitleAll();
   20: priceList = objDao.selectPriceAll();

 24行目ではdisplay()メソッドを呼び出して18行目から20行目で取得したデータを画面に表示しています。
   24: display();

 ここまでがデータベースからデータを取得し、表示するまでの流れになります。

 データの登録処理は27行目で行なっています。27行目ではSampleDAO1クラスのinsertBook()メソッドを呼び出し、引数に登録する書籍のisbn、title、price情報を渡します。insertBook()メソッド内では、引数の情報を基にSQL文を作成・実行し、戻り値として登録された行数(int型の値)を返します。
   27: int rowsCount = objDao.insertBook("00008", "Strutsテキスト", 2000);

図 4.1.4: insertBook()メソッドの流れ

 33行目から39行目では、18行目から24行目と同じ処理を行い、登録結果を表示しています。
   33: isbnList = objDao.selectIsbnAll();
   34: titleList = objDao.selectTitleAll();
   35: priceList = objDao.selectPriceAll();
   38: System.out.println("■登録SQL発行後の書籍一覧表示■");
   39: display();

 このプログラムではisbn、title、priceの3つのArrayListを取得する必要があるため、3種類のSELECTメソッドを記述し使用しています。メソッドの戻り値は1つの型しか返すことができないために、このようなプログラムになっていますが、あまり効率的なプログラムとは言えません。

 次の節では、データの受け渡しを効率よく行うために、DTOクラスについて学習します。

ポイント
  • DAOクラスを利用することでメインロジックとデータアクセスロジックを分けることができる。

NEXT>> 4.2 DAO/DTOパターン