【Spring MVC】DBアクセスの概要

概要

Spring MVCでは「データソース」と「データアクセスフレームワーク」を使用してDBアクセスを行う。
今回はそれぞれの概念について簡単にまとめた。

また、「データアクセスフレームワーク」を使用しない場合についてもあわせて紹介する。

 

データソース

データソースとは、DBやその他のデータストレージへの接続に必要な情報を保持するオブジェクトのこと
データソースは以下のような役割を持つ。

・接続管理: DBへの接続の作成、管理、閉鎖など
・コネクションプーリング: 事前にDB接続情報を保持し、必要に応じて再利用する
・トランザクション管理: 整合性を保ちながら、DBへの複数の操作を一連の処理として扱う

 

定義方法

データソースは以下のような情報を設定して定義する。

・DBサーバーのアドレス: DBがホストされているサーバーのIPアドレスやドメイン名
・ポート番号: DBサーバーが通信に使用するポート
・DB名: 接続する特定のDBの名前
・ユーザー名とパスワード: DBへのアクセスに必要な認証情報

Spring MVCではデータソースをDIコンテナで管理する。
そのため、上記のような情報をBean定義ファイルに設定する必要がある。

 

データアクセスフレームワーク

データアクセスフレームワークの目的は、アプリケーションとDB間のやり取りを簡素化し、効率化するためにある
Spring MVCでは、主に以下のようなものがある。

・Spring JDBC
・Spring Data JPA
・Spring + MyBatis

それぞれ使用方法については別の記事で紹介する。

 

フレームワークを使用しない場合

データアクセスフレームワークを使用しない場合、JDBC API(Javaの標準APIであるJDBC)を使用してDBアクセスを行う。
データアクセスフレームワークと異なり、手動で冗長な処理を記載することになる
※DBアクセス例外やコネクションクローズ等を手動で記載する必要がある等

以下、データアクセスフレームワークを使用しない例を紹介する。

 

コネクション情報の取得

データアクセスを行うためのコネクション情報を取得する。
クラスを分ける必要はないが、ここでは役割をわかりやすくするためユーティリティクラスにDBの接続情報取得メソッドを用意する。

SqlConnector.java


public class SqlConnector {
	/** DB接続情報 */
	private static String DB_URL = "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1";
	private static String DB_USER = "";
	private static String DB_PASS = "";
	
	/**
	 * コネクション情報を返却する
	 * @return コネクション情報
	 * @throws SQLException
	 */
	public static Connection getCon() throws SQLException{
		try {
			// JDBCドライバーのクラスをロード ①
			Class.forName("org.h2.Driver");
		} catch (ClassNotFoundException e) {
			throw new SQLException("JDBCドライバーのロードに失敗しました", e);
		}
		
		return DriverManager.getConnection(DB_URL, DB_USER, DB_PASS); // ②
	}
}

 

// JDBCドライバーのクラスをロード ②
Class.forName(“org.h2.Driver”);

org.h2.Driverというクラスを初期化し、DriverManagerに登録される。
※DBの種類ごとにDBアクセスを行うドライバーが異なる

 

return DriverManager.getConnection(DB_URL, DB_USER, DB_PASS); // ②

①で初期化したドライバクラスを使用してDBに接続し、DB接続情報を保持したオブジェクトを返却する。

 

DAOクラス

コネクション情報を取得し、JDBC APIを介してDB接続を行う。
以下ではシンプルな「全検索」、「1件検索」、「1件挿入」の処理の例を紹介する。

どのメソッドも細かい説明はしないが、フレームワークを使用しないと冗長な処理を記述することになる

StudentDao


public class StudentDao {
	/**
	 * 全件検索
	 * @return 生徒情報リスト
	 */
	public List<Student> findAll() {
		// SQL文
		String sql = "SELECT * FROM student";
		// SQL取得結果リスト
		var students = new ArrayList<Student>();
		// DB接続~SQL実行結果取得
		try (Connection conn = SqlConnector.getCon();
				PreparedStatement stmt = conn.prepareStatement(sql);
				ResultSet rs = stmt.executeQuery()) {

			while (rs.next()) {
				// 各カラム情報を取得
				int id = rs.getInt("id");
				int grade = rs.getInt("grade");
				String name = rs.getString("name");
				String className = rs.getString("class_name");
				String memo = rs.getString("memo");
				var student = new Student(id, grade, name, className, memo, null);
				// 生徒情報を格納
				students.add(student);
			}

		} catch (SQLException e) {
			throw new CustomDataAccessException("DB例外発生");
		}
		
		return students;
	}
	
	/**
	 * 指定したidに紐づく生徒情報の取得
	 * @param id 生徒ID
	 * @return 生徒情報
	 */
	public Optional<Student> findById(int id) {
        // SQL文
        String sql = "SELECT * FROM student WHERE id = ?";
        // DB接続~SQL実行結果取得
        try (Connection conn = SqlConnector.getCon();
             PreparedStatement stmt = conn.prepareStatement(sql)) {

            // IDをクエリパラメータとして設定
            stmt.setInt(1, id);

            try (ResultSet rs = stmt.executeQuery()) {
                if (rs.next()) {
                    // 各カラム情報を取得
                    int grade = rs.getInt("grade");
                    String name = rs.getString("name");
                    String className = rs.getString("class_name");
                    String memo = rs.getString("memo");
                    var student = new Student(id, grade, name, className, memo, null);
                    return Optional.of(student);
                }
            }

        } catch (SQLException e) {
            throw new CustomDataAccessException("DB例外発生: " + e.getMessage(), e);
        }

        return Optional.empty();
    }
	
	/**
	 * 生徒情報を追加
	 * @param student 追加する生徒情報
	 * @return true:追加成功、false:追加失敗
	 */
	public boolean addStudent(Student student) {
	    // SQL文(プレースホルダーを使用)
	    String sql = "INSERT INTO student (grade, name, class_name, memo) VALUES (?, ?, ?, ?)";
	    
	    // DB接続~SQL実行
	    try (Connection conn = SqlConnector.getCon();
	         PreparedStatement stmt = conn.prepareStatement(sql)) {
	        
	        // プレースホルダーに値をセット
	        stmt.setInt(1, student.getGrade());
	        stmt.setString(2, student.getName());
	        stmt.setString(3, student.getClassName());
	        stmt.setString(4, student.getMemo());

	        // SQL実行
	        int result = stmt.executeUpdate();

	        // 追加された行数をチェック
	        return result > 0;

	    } catch (SQLException e) {
	        // 例外処理
	        e.printStackTrace();
	        return false;
	    }
	}

}

 

DBアクセス

以下のようにDAOを呼び出してDBアクセスを行うことができる。

SampleMain.java


public class SampleMain {			
	public static void main(String[] args) {		
		// H2DBのテーブル初期化のため呼び出し	
		try (ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(	
						
			var dao = new StudentDao();
			
			// 1件追加
			var student = new Student(0, 2, "木村五郎", "2-B", "質実剛健", null);
			boolean addResult = dao.addStudent(student);
			System.out.println("挿入結果:" + addResult);
			// 全件検索
			dao.findAll().forEach(s -> System.out.println(s));
			// 1件検索
			var resStudent = dao.findById(3).orElse(null);
			System.out.println(resStudent);
		}	
	}		
}			

 

スポンサーリンク