SpringJDBCを試す
SpringJDBCを試してみました。
事前準備
PostgreSQLについてはdockerで構築しました。docker
コマンドが使える環境で以下を実行します。
docker run --name my-db -p 5432:5432 -e POSTGRES_USER=dev -e POSTGRES_PASSWORD=dev -d postgres:9.6
またサンプルデータとして利用するために以下のSQLを実行しておきます。
psqleditなどを利用して、dockerで立ち上げたPostgreSQLにログインできるか確認しておきましょう。
さて、ソース構成は以下のようにしました。Configurationはxmlで定義することにします。
└─src └─main ├─java │ └─sample │ │ Main.java │ │ │ ├─dao │ │ CustomerDao.java │ │ SampleDao.java │ │ │ └─model │ Customer.java │ └─resources │ datasource.xml │ jdbc.properties │ └─spring applicationContext.xml
データアクセスする際のアーキテクチャは以下のようになっています。
https://terasolunaorg.github.io/guideline/public_review/ArchitectureInDetail/DataAccessCommon.htmlより引用
試す
データソース(DataSource)
データソース(DataSource)はデータベースにアクセスするためのコネクションをアプリケーションに提供する役割を担います。データソースを使用することにより、プログラムの中でJDBCドライバーのロードなどを行う必要はなくなります。さらに、データベースに依存する部分がデータソースに吸収されるため、プログラムの可搬性も向上します。
今回はプロパティファイル(jdbc.properties)に値を保持し、dataSourceのBean定義に関してはdatasource.xmlに定義することにしました。
- jdbc.properties
database.driverClassName=org.postgresql.Driver database.url=jdbc:postgresql://localhost:5432/dev database.username=dev database.password=dev
- datasource.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans" 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"> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${database.driverClassName}" /> <property name="url" value="${database.url}" /> <property name="username" value="${database.username}" /> <property name="password" value="${database.password}" /> <property name="defaultAutoCommit" value="false" /> </bean> </beans>
以下でクラスパス上に存在するjdbc.propertiesを読み込みます。
<context:property-placeholder location="classpath:jdbc.properties"/>
データソースにはApacheのDBCPを利用しています。org.apache.commons.dbcp2.BasicDataSource
をBeanとして利用するためにBean定義をしています。また同時に jdbc.properties
で定義した各種設定を注入しています。
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${database.driverClassName}" /> <property name="url" value="${database.url}" /> <property name="username" value="${database.username}" /> <property name="password" value="${database.password}" /> <property name="defaultAutoCommit" value="false" /> </bean>
SpringJDBC
SpringJDBCとは、SQLの内容に関わらず共通的に行われる定型的なJDBCの処理をSpringが代替する機能です。例えば以下があります。
SpringJDBCを利用することで、実装範囲を以下のような重要な処理に限定することができます。
- SQLの定義
- パラメータの設定
- ResultSetの取得結果に対するロジックの実装
SpringJDBCの JdbcTemplate
を利用するために、applicationContext.xmlにBean定義をしておきます。
- applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans" 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"> <import resource="classpath:datasource.xml"/> <context:component-scan base-package="sample.dao" /> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg name="dataSource" ref="dataSource" /> </bean> </beans>
Daoクラスの実装
それぞれのDao @Repository
を付与してDIコンテナに登録しておきます。以下は1行を返却するDaoです。SpringJDBCのJdbcTemplateは @Autowired
で注入します。
- SampleDao.java
package sample.dao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class SampleDao { @Autowired JdbcTemplate jdbcTemplate; public int findCountDatabase() { String sql = "select count(1) from pg_database;"; return jdbcTemplate.queryForObject(sql, Integer.class); } }
このDaoクラスは以下のように利用できます。
SampleDao sampleDao = context.getBean(SampleDao.class); int databaseCount = sampleDao.findCountDatabase(); System.out.println(databaseCount); // 4
複数行の検索結果を扱う場合は以下が実装例です。SpringJDBCのRowMapperを利用することで取得結果のResultSetをPOJOに変換する機構を備えています。CustomerDao.javaではラムダ式でRowMapperのmapRowメソッドをoverrideしています。
- CustomerDao.java
package sample.dao; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import sample.model.Customer; @Repository public class CustomerDao { @Autowired JdbcTemplate jdbcTemplate; public List<Customer> getCustomerList() { String sql = "select id, firstname, lastname, street, city from customer order by id"; return jdbcTemplate.query(sql, (rs, rowNum) -> { Customer customer = new Customer(); customer.setId(rs.getInt("id")); customer.setFirstName(rs.getString("firstName")); customer.setLastName(rs.getString("lastName")); customer.setStreet(rs.getString("street")); customer.setCity(rs.getString("city")); return customer; }); } }
CustomerDao customerDao = context.getBean(CustomerDao.class); List<Customer> customerList = customerDao.getCustomerList(); for (Customer customer : customerList) { System.out.println(customer); } // Customer(id=0, firstName=Laura, lastName=Steel, street=429 Seventh Av., city=Dallas) // Customer(id=1, firstName=Susanne, lastName=King, street=366 - 20th Ave., city=Olten) // Customer(id=2, firstName=Anne, lastName=Miller, street=20 Upland Pl., city=Lyon) // Customer(id=3, firstName=Michael, lastName=Clancy, street=542 Upland Pl., city=San Francisco) // ...
あとがき
今回試したソースは以下においてあります。
次にやりたいこと
SpringJDBCのトランザクション関連について動作を確認したいですね。