概要
データアクセスフレームワークであるSpring JDBCを使用する方法についてまとめた。
当記事ではDAOの作成と、DBアクセスの動確を行う方法について紹介する。
※尚、DAOパターンとは何かについての説明は割愛する
前提
H2DBの用意やSpring JDBCの提供するTemplateクラスをDIコンテナに登録した前回の記事の続きとなる。
概要 データアクセスフレームワークであるSpring JDBCを使用して、H2DBにアクセスする方法についてまとめた。 当記事ではSpring JDBCの特徴と、H2DBにアクセスするための準備方法について紹介する。 […]
DAOの作成
DAOのインターフェースと実装は分割して作成する。
インターフェースと実装を分離する目的としては、テストの容易性や拡張性などがある。
※細かくは説明しないが、インターフェースと実装を分けておくと、なにかと便利になる
DAOのインターフェース
studentテーブルと疎通するインターフェースを作成する。
ここに必要なメソッドを用意することで、呼び出し元から実装の詳細を隠蔽する。
これにより、実装の中身に変更があっても呼び出し箇所には影響しない。
StudentDao.java
public interface StudentDao {
/** 生徒の合計数を取得 */
int getStudentsCount();
// 必要なメソッドを用意する
}
DAOの実装
DAOの実装クラスを作成する。
JdbcStudentDao.java
@Component // ①
public class JdbcStudentDao implements StudentDao {
@Autowired // ②
private JdbcTemplate jdbcTemplate;
/**
* 生徒数を取得する
*/
@Override
public int getStudentsCount() {
var sql = "SELECT COUNT(*) FROM student";
return jdbcTemplate.queryForObject(sql, Integer.class); // ③
}
}
DIコンテナにBean管理してもらうため、@Componentアノテーションまたは@Repositoryアノテーションをつける。
Spring JDBCの提供するTemplateクラスは、DBアクセス時の例外をDataAccessExceptionで一律ラップするが、@Repositoryアノテーションをつけた場合も同様となる。
private JdbcTemplate jdbcTemplate;
DIコンテナで登録しているjdbcTemplateをインジェクションしている。
NamedParameterJdbcTemplateを使用する場合、同様にインジェクションする必要がある。
Spring JDBCによるDBアクセス(SELECT処理)。
詳細は別の記事にて紹介するが、JDBC APIにて必要だった煩雑な処理がなくなったことがわかる。
コンポーネントスキャンの追加
Daoの実装クラスに「@Component」または「@Repository」をつけてDIコンテナに登録する準備が整うが、コンポーネントスキャンの対象としていないとBean管理されない。
Bean定義ファイルに、コンポーネント用アノテーションがついたクラスがBean管理されるよう、コンポーネントスキャンを設定する。
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
<!-- JdbcTemplateを使用する場合 -->
<bean class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
<!-- NamedParameterJdbcTemplateを使用する場合 -->
<bean
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
<!-- H2 DBのデータソース -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url"
value="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1" />
</bean>
<jdbc:initialize-database
data-source="dataSource">
<jdbc:script location="classpath:sql/schema.sql" />
<jdbc:script location="classpath:sql/data.sql" />
</jdbc:initialize-database>
<!-- コンポーネントスキャン -->
<context:component-scan base-package="com.example.prototype.biz" />
</beans>
<context:component-scan base-package=”com.example.prototype.biz” />
今回の場合、DAOの実装クラスであるJdbcStudentDao.javaは「com.example.prototype.biz」パッケージ配下に格納されている。
DAOの動確
WebアプリケーションではDB操作を行うため、DAOクラスを作成することになる。
その際にDAOクラスの動確を行うため、わざわざブラウザから導通するというのは手間がかかる。
そのため、ここではエントリポイントからDAOクラスの動確を行う方法について紹介する。
FooMain.java
// エントリポイント
public static void main(String[] args) {
try (var context = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml")) { // ①
// DIコンテナからStudentDaoを取得
var studentDao = context.getBean(StudentDao.class); // ②
// 処理を記載
}
}
DIコンテナ(アプリケーションコンテキスト)を取得する。
上記によりアプリケーションコンテキストがロードされて、H2DBのテーブルも初期化される。(前提項目に掲載している前回の記事参照)
var studentDao = context.getBean(StudentDao.class); // ②
DIコンテナからStudentDaoを取得する。
実際にはDIコンテナに登録している、実装クラスのJdbcStudentDaoがインジェクションされる。
例外ハンドリング
Spring JDBCの提供するTemplateクラスを使用してDBアクセスを行う際に、DBアクセス例外はすべてDataAccessExceptionにラップされる。
これは非検査例外(Runtime系)なので、try-catchは強制されない。
もし例外ハンドリングを行いたい場合、以下のように対応する。
・@ExceptionHandlerでDataAccessExceptionをハンドリング
@ExceptionHandlerについてはコントローラー側に通知される例外をハンドリングすることになるため、エントリポイントからDAOを実行する際の例外はハンドリングできないので注意。
概要 Spring MVCを使用したWebアプリケーションにて、例外ハンドリングを行う方法についてまとめた。 例外ハンドリングはweb.xmlまたはHandlerExceptionResolverの実装によって行う。 当記事ではH[…]