支援対象地域:札幌、仙台、関東、愛知、関西、広島、福岡


はじめに

Springは、Javaでアプリケーションを作成する上で欠かすことのできないフレームワークです。 Springでデータアクセス層にアクセスするために用いられるSpring JDBCについてご紹介します。

以下の内容をご紹介します。



(1)Springにおけるデータアクセス技術

データベースにアクセスする技術として、JDBCHibernateJPAなどがあります。
Springは新たなデータアクセス技術ではなく、既存のデータアクセス技術をより使いやすくするための連携機能を提供しています。
Springと連携したJDBCがSpring JDBCというわけです。

1-1 Springを用いるメリット

Springと連携することで様々なメリットを得られます。
《Springとの連携で得られるメリット》
  • データアクセス処理がシンプルになる
  • Springのトランザクション機能を利用できる
  • Springの提供する体系化されたデータアクセス例外を利用できる
  • Springがデータアクセス技術独自の例外を汎用的なデータベース例外に変換してくれる。
    【Springに用意されている汎用的なデータアクセス例外の例】
    例外クラス エラーの原因
    DataAccessResourceFailureException データソースとの接続に失敗
    BadSqlGrammarException SQLの文法エラー
    EmptyResultDataAccessException 取得できるはずのデータが存在しない
    ConcurrencyFailureException 同時実行の失敗
    DeadlockLoserDataAccessException デッドロックの発生
    DuplicateKeyException データの挿入・更新時に主キー or 一意制約に違反
    DataIntegrityViolationException データの挿入・更新時に整合性制約に違反
    PermissionDeniedDataAccessException 特定の要素(DBテーブルなど)へのアクセスが許可されていない

1-2 データベース接続管理

データベースに接続する場合は、データベースに接続するための必要な情報(JDBCドライバー、データベースURL、ユーザ名、パスワード 等)を管理してくれるデータソースを準備する必要があります。また、変更を容易にするため、データベースに接続するための必要な情報は、プロパティファイルを準備して記述しましょう。
今回は、Apacheソフトウェア財団がOSSとして提供しているDBCP(Apache Commons DBCP)をXML形式のBean定義ファイルで用いたデータソースの実装についてご紹介します。
<!-- XML形式のBean定義ファイル -->

<?xml version="1.0" encoding="UTF-8"?>
<!-- スキーマの使用はbeansタグ内でスキーマを定義する必要がある -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:context="http://www.springframework.org/schema/context"
    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.xsd
		http://www.springframework.org/schema/jee
		http://www.springframework.org/schema/jee/spring-jee.xsd
		http://www.springframework.org/schema/jdbc
		http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
		http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx.xsd
		http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">


<!-- location属性にプロパティファイルのパスを指定する -->
	<context:property-placeholder location="application.properties"/>

<!-- DBCPのデータソース定義箇所 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
	</bean>

<!-- XML形式のBean定義ファイルにおけるBean定義 -->
<!-- JdbcTemplateクラスのBean定義 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<constructor-arg ref="dataSource"/>
	</bean>
<!-- NamedParameterJdbcTemplateクラスのBean定義 -->
	<bean class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
		<constructor-arg ref="dataSource"/>
	</bean>
</beans>
#データベースに接続するための必要な情報を記述したプロパティファイル

jdbc.driverClassName = com.mysql.cj.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/db_ex?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
jdbc.username = root
jdbc.password = forStudy
【プロパティファイルの活用イメージ】


(2)Spring JDBCの利用

Spring JDBCには、2つの主なクラスがあります。
《Spring JDBCのクラス》
  • JdbcTemplateクラス
  • メソッドの種類が豊富であり、直接利用できるAPIの範囲も広い。
  • NamedParameterJdbcTemplateクラス
  • SQLのパラメータに任意の名前を付けてSQL文を発行するメソッドが提供されている。
これらのクラスのオブジェクトは、XML形式のBean定義ファイルもしくはJavaConfigでBean定義を行う必要があります。(XML形式のBean定義ファイルにおけるBean定義、JavaConfigは省略)

2-1 SQLの発行方法(SELECT文)

SELECE文のSQLを発行する場合に用いる代表的なメソッドをご紹介します。
《SELCT文発行メソッド》
1レコードを処理する場合に使用するメソッド
queryForObject(String sql , ClassSE<T> requiredType , Object args…);

第1引数:SQLを文字列で指定
第2引数:戻り値の型を示すClassオブジェクトを指定
第3引数以降:SQL内のパラメータ()の値を指定
:SQL文中で値を確定させるのではなく、実行時に値を代入することを示す位置指定子です。「?」を用います。
複数のレコードを処理する場合に使用するメソッド
query(String sql , ResultSetExtractor<T> rse , Object args…);

第1引数:SQLを文字列で指定
第2引数:ドメインに変換して戻り値で返す処理を記述する
第3引数以降:SQL内のパラメータの値を指定
queryForObject()メソッドとquery()メソッドの違いは、レコードを1件ずつ処理する複数まとめて処理するかです。ドメインに変換するqueryForObject()メソッドもあります。
queryForObject()メソッドやquery()メソッドはオーバーロードによりいくつかの種類が存在するので、それらについては、SpringのJavadocを参照してください。

2-2 SQLの発行方法(INSERT/UPDATE/DELETE文)

INSERT/UPDATE/DELETE文の発行は、update()メソッドを使うだけです。
《INSERT/UPDATE/DELETE文発行メソッド》
update(String sql , Object args…);

第1引数:SQLを文字列で指定
第2引数以降:SQL内のパラメータの値を指定

サンプルコード

Spring JDBCを用いてデータベース操作を行うサンプルコードをご紹介します。 各クラスの階層関係及び使用するデータベースは、次のようになります。

【各クラスの階層関係】

【データベース接続環境】
ユーザ名 root
パスワード forStudy
ホスト名 localhost
ポート番号 3306
データベース名 db_ex

【テーブル:商品一覧】
列名 データ型 制約
id INT NOT NULL , PRIMARY KEY
name VARCHAR(100) -
price INT -

id
INT
name
VARCHAR(100)
price
INT
1 ○○○小説 800
2 ABC資格 参考書 2500
3 ABC資格 問題集 2800
4 △△△技術書 4200
5 □□□漫画全巻 3200

//プレゼンテーション層パッケージ
package sample;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;

import sample.springjdbc.bujiness.domain.Book;

//コントローラの代わとしてmain()メソッドを実行する
public class SampleRun {

	public static void main(String[] args) {
		//SpringコンテナをBean定義ファイルにより生成
		String classPath = "sample/config/spring-db.xml";
		ApplicationContext ctx = new ClassPathXmlApplicationContext(classPath);

		//JdbcTemplateオブジェクトを取得
		JdbcTemplate jdbcTemplate = ctx.getBean(JdbcTemplate.class);

		//SELECT文
		//queryForObjectメソッド
		String sql = "SELECT COUNT(*) FROM 商品一覧";
		int count = jdbcTemplate.queryForObject(sql, Integer.class);
		System.out.println("レコード数:" + count + "件"+ "¥n");

		//SELECT文
		//queryメソッド
		sql = "SELECT * FROM 商品一覧";
		Book book = jdbcTemplate.query(sql
				, new ResultSetExtractor<Book>() {
					public Book extractData(ResultSet rs) throws SQLException ,DataAccessException {
					if (!rs.next()) { return null; }
					Book book = new Book();
					while (rs.next()) {
						System.out.println("id : " + rs.getInt("ID"));
						System.out.println("name : " + rs.getString("NAME"));
						System.out.println("price : " + rs.getInt("PRICE") + "¥n");
					}
					return book;
				 }}
				);


		// INSERT/UPDATE/DELETE 文
		//INSERT文
		book = new Book();
		book.setId(6);
		book.setBookName("123書籍");
		book.setPrice(2700);
		//INSERT文
		sql = "INSERT INTO 商品一覧 (ID , NAME , PRICE)"
					+ "VALUES(? , ? , ?)";
		jdbcTemplate.update(sql , book.getId() , book.getBookName() , book.getPrice());

		//UPDATE文
		sql = "UPDATE 商品一覧 SET PRICE = 9999 WHERE ID = ?";
		jdbcTemplate.update(sql , book.getId());

		System.out.println("INSERT/UPDATE後");
		sql = "SELECT * FROM 商品一覧";
		book = jdbcTemplate.query(sql
				, new ResultSetExtractor<Book>() {
					public Book extractData(ResultSet rs) throws SQLException ,DataAccessException {
					if (!rs.next()) { return null; }
					Book book = new Book();
					while (rs.next()) {
						System.out.println("id : " + rs.getInt("ID"));
						System.out.println("name : " + rs.getString("NAME"));
						System.out.println("price : " + rs.getInt("PRICE") + "¥n");
					}
					return book;
				 }}
				);

		//DELETE文
		sql = "DELETE FROM 商品一覧 WHERE ID = 6";
		jdbcTemplate.update(sql);
	}
}
//ビジネスロジック層(ドメイン)パッケージ
package sample.springjdbc.bujiness.domain;

public class Book {
	private Integer id;
	private String bookName;
	private Integer price;

	public Integer getId() { return id; }
	public void setId(Integer id) { this.id = id; }

	public String getBookName() { return bookName; }
	public void setBookName(String bookName) { this.bookName = bookName; }

	public Integer getPrice() { return price; }
	public void setPrice(Integer price) { this.price = price; }
}
実行結果
レコード数:5件

id : 2
name : ABC資格 参考書
price : 2500

id : 3
name : ABC資格 問題集
price : 2800

id : 4
name : △△△技術書
price : 4200

id : 5
name : □□□漫画全巻
price : 3200
INSERT/UPDATE後
id : 2
name : ABC資格 参考書
price : 2500

id : 3
name : ABC資格 問題集
price : 2800

id : 4
name : △△△技術書
price : 4200

id : 5
name : □□□漫画全巻
price : 3200

id : 6
name : 123書籍
price : 9999

まとめ

Spring JDBC」についてご紹介しました。
お役に立てると幸いです。